Symbols
A Symbol is a value that is guaranteed to be unique. It sounds abstract, but symbols are how JavaScript lets you plug your own objects into language features like for…of.
On this page · 5 min · Intermediate
On this page
- Learning objectives
- Explanation
- Syntax
- Code example
- Step by step
- Real-world use
- Common mistakes
- Best practices
- Remember this
- Practice exercise
- Mini quiz
- Related topics
- My notes
- Reading time
- 5 min
- Difficulty
- Intermediate
- Updated
- Oct 28, 2026
Related tutorials
Learning objectives#
- Create symbols and use them as object keys
- Explain why symbol keys do not clash
- Use Symbol.for for shared symbols
- Customise behaviour with well-known symbols
Explanation#
Symbol("id") creates a brand-new unique value. Two symbols with the same description are still different: Symbol("x") !== Symbol("x").
Used as an object key, a symbol cannot clash with any string key or with another library’s symbol. Symbol keys are skipped by Object.keys, for…in and JSON.stringify.
Symbol.for("app") looks up a global registry: the same name always returns the same symbol, even across files.
Well-known symbols are hooks into the language: Symbol.iterator makes an object work with for…of and spread; Symbol.toPrimitive controls how an object converts to a string or number.
Syntax#
const id = Symbol('id');
const obj = { [id]: 123 };
obj[id]; // 123
Code example: Unique keys and language hooks#
const id = Symbol('id');
const user = { name: 'Asha', [id]: 101 };
console.log(user[id]);
console.log(Object.keys(user));
console.log(JSON.stringify(user));
console.log(Symbol('x') === Symbol('x'));
console.log(Symbol.for('app') === Symbol.for('app'));
class Temperature {
constructor(c) { this.c = c; }
[Symbol.toPrimitive](hint) {
return hint === 'string' ? `${this.c}°C` : this.c;
}
}
const t = new Temperature(30);
console.log(`${t}`, t + 5);
101
[ 'name' ]
{"name":"Asha"}
false
true
30°C 35Step-by-step explanation#
- The symbol key stores 101 and is read with user[id].
- Object.keys and JSON.stringify ignore symbol keys — the id stays hidden.
- Two Symbol() calls are always different.
- Symbol.for returns the same registered symbol for the same name.
- Symbol.toPrimitive decides the conversion: string in a template literal, number in maths.
Real-world use case#
Libraries attach metadata to your objects with symbol keys so they never overwrite your own properties; custom collections implement Symbol.iterator.
Common mistakes#
JSON.stringify drops symbol keys. Use string keys for data you send to a server.
Object.getOwnPropertySymbols(obj) reveals them. Use #private class fields for real privacy.
Symbol is not a constructor; new Symbol() throws a TypeError. Call Symbol() directly.
Best practices#
- Use symbols for metadata keys that must not clash
- Use well-known symbols to integrate with language features
- Always give symbols a description for debugging
- Use Symbol.for only when sharing across modules is intended
Remember this#
Symbol = a one-of-a-kind ID tag.
Hidden from keys, loops and JSON — but not truly private.
Symbol.iterator = “I can be looped”. Symbol.toPrimitive = “here is how to convert me”.
Practice exercise#
Your task: Create a Money class whose instances print as "₹500" in template literals and behave as 500 in arithmetic.
Need a hint?
Show solution
class Money {
constructor(amount) { this.amount = amount; }
[Symbol.toPrimitive](hint) { return hint === 'string' ? `₹${this.amount}` : this.amount; }
}
const m = new Money(500);
console.log(`${m}`, m * 2); // ₹500 1000
Mini quiz#
What is printed?
console.log(Symbol('a') === Symbol('a'));
Want more? Practise all ES6+ MCQs · ES6+ interview questions
My notes#
Saved in this browser.