Symbols & Well-Known Symbols
A Symbol is a unique, primitive value created with Symbol() that serves as a collision-proof object key and lets you hook into built-in language behaviors through well-known symbols like Symbol.iterator .
Learn Symbols & Well-Known Symbols in our free JavaScript course — an interactive lesson with runnable examples, a practice exercise and a quick reference.
Part of the free JavaScript course at LearnCodingFast — hands-on lessons with examples you run in your browser, plus practice exercises and a quick quiz.
Symbols are how you add hidden, non-colliding metadata to objects and how you teach your own objects to work with for...of , spread, and type coercion.
📚 Prerequisites: You should know objects, object iteration , and the idea of primitive types. Symbols are a primitive type just like numbers and strings.
🔣 Real-World Analogy: A Symbol is like a numbered cloakroom ticket :
Symbol("desc") returns a value guaranteed to differ from every other symbol. The string you pass is only a description for debugging — two symbols with the same description are still not equal. Used as object keys, symbols never clash with string keys, and they're invisible to for...in , Object.keys , and JSON.stringify , which makes them ideal for private-ish metadata.
Not truly private: symbol keys are hidden from normal iteration but Object.getOwnPropertySymbols can still find them. Use them for de-facto privacy, not security.
Plain Symbol() is private and unshareable. When you need the same symbol in different places, use Symbol.for("key") : it looks up a global registry, creating the symbol once and returning that identical symbol on every later call — even from another module. Symbol.keyFor recovers the registry key from such a symbol.
Namespace your keys (e.g. "myapp.userId" ) so registry symbols from different libraries don't accidentally collide on a common word.
JavaScript reserves a set of well-known symbols to customize language behavior. Define a [Symbol.iterator] method and your object suddenly works with for...of and the spread operator. Define [Symbol.toPrimitive] and you control how your object converts to a number or string in arithmetic and template literals.
Iterables power the language: arrays, strings, Maps, and Sets are all iterable because they implement Symbol.iterator . Now your objects can join the club.
Add a symbol key to the object so it stays out of Object.keys .
Predict the output before revealing the answer.
false — every Symbol() call makes a new, unique value.
true — Symbol.for returns the same registry symbol for a given key.
{' '} — symbol keys are skipped by JSON.stringify .
Make a team object iterable so spreading it yields its member names.
Up next: Getters, Setters & Property Descriptors — computed and protected properties. ⚙️
Practice quiz
What is logged? console.log(Symbol('id') === Symbol('id'));
- true
- undefined
- false
- It throws
Answer: false. Every Symbol() call makes a brand-new unique value; the description does not affect identity.
What is the role of the string passed to Symbol('id')?
- It is just a description for debugging
- It makes equal symbols
- It registers the symbol globally
- It sets the symbol's value
Answer: It is just a description for debugging. The description is only a debugging label; two symbols with the same description are still unequal.
What does Symbol.for('app.id') === Symbol.for('app.id') evaluate to?
- false
- undefined
- It throws
- true
Answer: true. Symbol.for looks up a shared global registry, returning the same symbol for a given key every time.
How are symbol keys treated by Object.keys and JSON.stringify?
- They are included
- They are skipped/hidden
- They cause an error
- They are converted to strings
Answer: They are skipped/hidden. Symbol keys are invisible to for...in, Object.keys, and JSON.stringify — handy for de-facto private metadata.
Which method reveals symbol keys that Object.keys omits?
- Object.getOwnPropertySymbols
- Object.entries
- Object.getOwnPropertyNames
- Reflect.keys
Answer: Object.getOwnPropertySymbols. Object.getOwnPropertySymbols lists an object's symbol keys.
Defining a [Symbol.iterator] method on an object lets it work with:
- JSON.stringify
- Math operations
- for...of and the spread operator
- Object.freeze
Answer: for...of and the spread operator. Symbol.iterator is a well-known symbol that enables for...of and spread on your object.
What does Symbol.toPrimitive let you control?
- JSON serialization
- How the object converts to a number or string
- Garbage collection
- Property enumeration order
Answer: How the object converts to a number or string. Symbol.toPrimitive customizes coercion in arithmetic and template literals.
What is logged? console.log('id: ' + Symbol('x'));
- 'id: Symbol(x)'
- 'id: undefined'
- An empty string
- A TypeError
Answer: A TypeError. Implicitly coercing a symbol to a string with + throws; use .toString() or String() explicitly.
How do you use a symbol stored in a variable sym as an object key?
- { sym: 1 }
Use a computed key { [sym]: 1 }; { sym: 1 } would just use the string 'sym'.
What does Symbol.keyFor return for a symbol created with plain Symbol('z')?
- 'z'
- An empty string
- undefined
- It throws
Answer: undefined. Symbol.keyFor only finds registry symbols (from Symbol.for); a private Symbol() returns undefined.