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.
What You'll Learn in This Lesson
📚 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 :
- • Two tickets can say "coat" (the description) but each is still a different ticket
- • Only the holder of the exact ticket can claim that coat — no accidental mix-ups
- • Symbol.for("vip") is a season pass : ask for the same name and you always get the same shared pass
1️⃣ Unique Values & Non-Colliding Keys
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.
2️⃣ The Global Registry: Symbol.for & Symbol.keyFor
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.
3️⃣ Well-Known Symbols: iterator & toPrimitive
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.
🎯 Your Turn — A Hidden Key
Add a symbol key to the object so it stays out of Object.keys .
🧠 Quick Recall
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.
{"a":2} — symbol keys are skipped by JSON.stringify .
Common Errors & Fixes
- 1️⃣ Expecting equal descriptions to mean equal symbols
- 2️⃣ Coercing a symbol to a string with +
- 3️⃣ Using a symbol as a key without brackets
- 4️⃣ Expecting symbol keys in Object.keys
🎯 Mini Challenge — Custom Iterable
Make a team object iterable so spreading it yields its member names.
Quick Reference
Expression
Meaning
Symbol("d")
new unique value
Symbol.for("k")
shared registry symbol
{ [sym]: v }
symbol as a key
Symbol.iterator
enables for...of / spread
Symbol.toPrimitive
controls coercion
📚 Keep Learning
- MDN: Symbol reference
- MDN: Symbol.iterator
- MDN: Symbol.for()
Frequently Asked Questions
🎉 Lesson Complete — Symbols!
- ✅ Symbol() creates a guaranteed-unique value
- ✅ Symbol keys never collide and are hidden from loops & JSON
- ✅ Symbol.for shares one symbol via the global registry
- ✅ Symbol.iterator makes objects work with for...of and spread
- ✅ Symbol.toPrimitive customizes coercion
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.
Continue this course
- Previous: Object Methods
- Next: Getters, Setters & Property Descriptors