Symbol
Introduction
Symbol is a primitive type whose values are guaranteed to be unique. Symbols are often used as non-colliding object property keys and as hooks into JavaScript protocols such as iteration via Symbol.iterator.
Symbol('id') and another Symbol('id') have the same description but are different values. Symbol.for('id') uses a global registry and can return the same symbol for the same key.
Why This Matters
Symbols are less common than strings and numbers, but they are high-signal in interviews. They reveal whether you understand property keys, enumeration, uniqueness, and language protocols like for...of and custom iterables.
Theory
Unique primitive identifiers
Every call to Symbol(description) returns a new unique primitive. The description is only for debugging; it does not participate in equality.
| Use case | Symbol role | Example |
|---|---|---|
| Avoid property-name collisions | Unique object key | Library metadata on user objects. |
| Hide from common enumeration | Symbol keys skipped by Object.keys and JSON | Internal-ish fields. |
| Well-known protocols | Built-in symbols customize behaviour | Symbol.iterator, Symbol.toStringTag. |
| Shared symbol by key | Global registry | Symbol.for('app.id'). |
Symbols as property keys
Object property keys can be strings or symbols. Symbol-keyed properties are not returned by Object.keys, for...in, or JSON serialization. They are still real properties and can be retrieved with Object.getOwnPropertySymbols or Reflect.ownKeys.
Well-known symbols
JavaScript defines well-known symbols that engines look for to customize behaviour. The most important early example is Symbol.iterator: if an object has a method at that key, for...of can iterate it.
Global symbol registry
Symbol.for(key) checks a runtime-wide registry. If a symbol for the key exists, it returns it; otherwise it creates one. Symbol.keyFor(symbol) returns the registry key for registered symbols, but returns undefined for local symbols created with Symbol().
Visual Diagrams
Symbol('id') -> unique A
Symbol('id') -> unique B
A !== B
Symbol.for('id') -> registry symbol R
Symbol.for('id') -> same registry symbol RDescriptions are not identities. The global registry is the exception when you intentionally want sharing.
Code Examples
Symbol property keys
Symbol keys avoid collisions and are skipped by common string-key enumeration APIs.
A custom iterable with Symbol.iterator
for...of looks for a method stored under the well-known Symbol.iterator key.
Playground
Press Run to execute the code and see output here.
Output Prediction
Predict the output #1
1const a = Symbol('id');2const b = Symbol('id');3console.log(a === b);4 5const c = Symbol.for('id');6const d = Symbol.for('id');7console.log(c === d);8 9const secret = Symbol('secret');10const user = { name: 'Ada' };11user[secret] = 99;12 13console.log(JSON.stringify(Object.keys(user)));14console.log(user[secret]);15console.log(JSON.stringify(user));Coding Exercises
Create an iterable range
MediumImplement makeRange(start, end) so the returned object can be used in for...of and yields every integer from start through end inclusive. Use Symbol.iterator directly.
Interview Questions
1What are Symbols used for in JavaScript?
Symbols are unique primitive values commonly used as object property keys that cannot collide with normal string keys. They are skipped by common enumeration methods like Object.keys and JSON serialization. Well-known symbols such as Symbol.iterator let objects participate in language protocols. Symbol.for is used when you intentionally want a shared symbol from the global registry.
Follow-ups
- Are symbol properties private?
- What is the difference between `Symbol()` and `Symbol.for()`?
Quiz
1. What is `Symbol('x') === Symbol('x')`?
2. Which API returns symbol keys from an object?
Summary
- `Symbol()` creates a unique primitive value, even when descriptions match.
- Symbols can be object property keys and avoid name collisions.
- Symbol-keyed properties are skipped by `Object.keys`, `for...in`, and JSON serialization.
- Well-known symbols like `Symbol.iterator` customize language protocols; `Symbol.for` uses a global registry.
Cheat Sheet
Create: const key = Symbol('debug description').
Unique: Symbol('x') !== Symbol('x').
Registry: Symbol.for('x') === Symbol.for('x'); Symbol.keyFor.
Object keys: use obj[key]; find with Object.getOwnPropertySymbols or Reflect.ownKeys.
Protocols: Symbol.iterator enables for...of.