Symbols
MedSymbol is JavaScript's 7th primitive type, introduced in ES6. Every Symbol() call creates a completely unique value — even two symbols with the same description are different. Symbols serve as collision-free property keys and enable metaprogramming through well-known symbols like Symbol.iterator and Symbol.toPrimitive.
Interactive Visualization
Built-in Data Structures
"age":30
Key Points
- Symbol() creates a guaranteed-unique value every time — no two symbols are ever equal
- Symbol.for(key) uses a global registry — same key returns the same symbol across realms
- Well-known symbols (Symbol.iterator, Symbol.toPrimitive, Symbol.hasInstance) customize language behavior
- Symbols as property keys are not enumerable by for...in or Object.keys()
- Symbol.description provides a read-only description string for debugging
- Symbols cannot be implicitly converted to strings — must use .toString() or .description
Code Examples
Creating and Using Symbols
const sym1 = Symbol('id') const sym2 = Symbol('id') console.log(sym1 === sym2) // false — always unique! const user = { name: 'Alice', [sym1]: 'hidden-id-001', } console.log(user[sym1]) // 'hidden-id-001' console.log(Object.keys(user)) // ['name'] console.log(Object.getOwnPropertySymbols(user)) // [Symbol(id)]
Symbols are unique identifiers perfect for property keys that should not collide with string keys.
Symbol.for() Global Registry
const s1 = Symbol.for('app.id') const s2 = Symbol.for('app.id') console.log(s1 === s2) // true — same key, same symbol! console.log(Symbol.keyFor(s1)) // 'app.id' const s3 = Symbol('app.id') console.log(s1 === s3) // false — not in registry
Symbol.for() enables sharing symbols across files and realms. Regular Symbol() always creates a new unique value.
Well-Known Symbol: Symbol.toPrimitive
class Temperature { constructor(celsius) { this.celsius = celsius } [Symbol.toPrimitive](hint) { switch (hint) { case 'number': return this.celsius case 'string': return `${this.celsius}°C` case 'default': return this.celsius } } } const temp = new Temperature(36.6) console.log(+temp) // 36.6 (number) console.log(`Body: ${temp}`) // 'Body: 36.6°C' (string) console.log(temp > 37) // false (number)
Symbol.toPrimitive lets you control how an object converts to primitive values in different contexts.
Symbol.hasInstance
class EvenNumber { static [Symbol.hasInstance](num) { return typeof num === 'number' && num % 2 === 0 } } console.log(2 instanceof EvenNumber) // true console.log(3 instanceof EvenNumber) // false console.log(100 instanceof EvenNumber) // true
Symbol.hasInstance customizes instanceof, enabling duck-type checking.
Common Mistakes
- Using Symbol() with new — Symbol is not a constructor, new Symbol() throws
- Expecting symbols to appear in for...in or Object.keys()
- Confusing Symbol() with Symbol.for() — former is always unique, latter uses shared registry
- Trying to concatenate symbols with strings implicitly — throws TypeError
Interview Tips
- Symbols solve the name collision problem for object properties
- Know at least 3 well-known symbols: Symbol.iterator, Symbol.toPrimitive, Symbol.hasInstance
- Understand Symbol() (always unique) vs Symbol.for() (shared registry)
- JSON.stringify ignores symbol-keyed properties