JavaScript Notes
Master JavaScript Symbols: unique primitive type, Symbol.iterator, Symbol.toPrimitive, well-known symbols, use cases, WeakMap comparison, and interview Q&A.
What are Symbols?
Symbol is a primitive data type introduced in ES2015. Every Symbol() call creates a guaranteed unique value — no two symbols are ever equal, even if created with the same description.
Symbols are primarily used as unique, collision-free object property keys — especially for metadata, protocols, and extending built-in behavior without risk of naming conflicts.
One-liner: A Symbol is a guaranteed-unique primitive value, perfect for object keys that should never accidentally conflict with other keys.
Creating Symbols
const sym1 = Symbol();
const sym2 = Symbol();
const sym3 = Symbol("description");
const sym4 = Symbol("description");
console.log(sym1 === sym2); // false — always unique
console.log(sym3 === sym4); // false — description ≠ identity
console.log(typeof sym1); // "symbol"
console.log(sym3.toString()); // "Symbol(description)"
console.log(sym3.description); // "description"false false symbol Symbol(description) description
Symbols as Object Keys
The primary use of symbols — create property keys that won't clash:
Priya 101 abc
Symbols Are Hidden in for...in and Object.keys()
Symbol properties are non-enumerable by default:
name
age
["name", "age"]
{"name":"Aman","age":25}
[Symbol(id)]Symbol.for() — Global Symbol Registry
Symbol.for(key) creates a shared symbol in a global registry — same key returns the same symbol:
const s1 = Symbol.for("shared");
const s2 = Symbol.for("shared");
console.log(s1 === s2); // true — same symbol from registry!
console.log(Symbol.keyFor(s1)); // "shared"
// vs regular Symbol:
const r1 = Symbol("regular");
const r2 = Symbol("regular");
console.log(r1 === r2); // false — always uniquetrue shared false
Use Symbol.for() when you need a symbol that multiple modules/parts of your app can share.
Well-Known Symbols
JavaScript defines built-in symbols that control core language behavior. You implement these to customize how your objects behave:
| Symbol | Controls |
|---|---|
Symbol.iterator | How object behaves in for...of, spread ... |
Symbol.toPrimitive | How object converts to primitive (string/number/default) |
Symbol.toStringTag | Custom result of Object.prototype.toString.call(obj) |
Symbol.hasInstance | Custom instanceof behavior |
Symbol.species | Which constructor to use for derived objects |
Symbol.asyncIterator | How object behaves in for await...of |
Symbol.iterator — Custom Iterable
1 2 3 4 5 [1, 2, 3, 4, 5]
By implementing [Symbol.iterator], Range works with for...of, spread, and destructuring.
Symbol.toPrimitive — Custom Type Coercion
Temperature: 25°C 25 true
Symbol.toStringTag — Custom Type Tag
[object Database] [object Database]
Simulating Private Properties with Symbols
Before #privateField syntax, symbols offered semi-private properties:
Ananya true false ["name"]
Comparing Symbol with String Keys
| Feature | String Key | Symbol Key |
|---|---|---|
| Uniqueness | ❌ Can conflict | ✅ Always unique |
| Enumerable in for...in | ✅ Yes | ❌ No |
| In JSON.stringify | ✅ Yes | ❌ No |
| In Object.keys() | ✅ Yes | ❌ No |
| In Object.getOwnPropertySymbols() | ❌ No | ✅ Yes |
| Global shared | N/A | Symbol.for() |
| Use for protocols | ❌ Risky | ✅ Perfect |
Common Mistakes
❌ Mistake 1 — Using new Symbol()
const s = new Symbol(); // TypeError: Symbol is not a constructorTypeError: Symbol is not a constructor
// CORRECT — no `new`
const s = Symbol("id");❌ Mistake 2 — Thinking Two Symbols with Same Description Are Equal
const a = Symbol("key");
const b = Symbol("key");
console.log(a === b); // false — description is just a label
console.log(a.toString()); // "Symbol(key)"
console.log(b.toString()); // "Symbol(key)"false Symbol(key) Symbol(key)
The description is a debugging label only — it doesn't affect uniqueness.
❌ Mistake 3 — Accessing Symbol Key with Dot Notation
undefined 42
Interview Questions 🎯
Q1. What is a Symbol in JavaScript?
A Symbol is a primitive data type that creates a guaranteed-unique value. Even two Symbols with the same description are not equal (Symbol("x") !== Symbol("x")). Used as collision-free object property keys.
Q2. Why are Symbols useful as object keys?
String keys can accidentally conflict (library A and library B both add a "type" property). Symbol keys are always unique — even if two libraries independently create Symbol("type"), they're different symbols and won't collide.
Q3. What is the difference between Symbol() and Symbol.for()?
Symbol(): creates a new unique symbol every timeSymbol.for(key): checks the global symbol registry; returns existing symbol for that key or creates a new one. Two calls with the same key return the same symbol.
Q4. Are Symbol properties visible in for...in or Object.keys()?
No. Symbol properties are non-enumerable by default. They don't appear in for...in, Object.keys(), Object.values(), or JSON.stringify(). Use Object.getOwnPropertySymbols(obj) to see them.
Q5. What are well-known Symbols and why do they matter?
Well-known Symbols are built-in symbols on the Symbol object (like Symbol.iterator, Symbol.toPrimitive) that control how JavaScript's built-in operations interact with your objects. Implementing them on a class customizes behavior like iteration, type coercion, and instanceof.
Q6. Can you use a Symbol in JSON.stringify?
No. JSON.stringify() silently ignores Symbol keys and Symbol values. If you need to serialize Symbol data, you must convert it to strings first.
Q7. What is Symbol.iterator and how do you implement it?
Symbol.iterator is a well-known symbol that defines how an object behaves when iterated. Implement it as a method returning an iterator object ({ next() { return { value, done } } }). Once implemented, your object works with for...of, spread, and destructuring.
Q8. How do Symbols compare to private class fields (#)?
Both provide "private" behavior:
- Symbols: Not truly private —
Object.getOwnPropertySymbols()can find them. Useful for protocols/metadata. - Private class fields (
#name): Truly private — enforced by the engine, completely inaccessible outside the class. Preferred for actual privacy in modern JavaScript.
Key Takeaways 🔑
- Every
Symbol()creates a unique primitive —Symbol("x") !== Symbol("x") - Symbols make collision-free object keys — perfect for extending objects safely
- Symbol properties are hidden from
for...in,Object.keys(), andJSON.stringify() Symbol.for(key)creates/retrieves shared global symbols from the registry- Well-known Symbols (
Symbol.iterator,Symbol.toPrimitive, etc.) customize built-in behavior Symbol.iteratorenablesfor...ofon custom objectsSymbol.toPrimitivecontrols type coercion- No
new Symbol()— symbols are created with a plain function call
Summary
Symbol is JavaScript's seventh primitive type — a guaranteed-unique value designed for use as collision-free object property keys. Unlike strings, two symbols are never equal even with identical descriptions. Symbols are hidden from common enumeration methods (for...in, Object.keys(), JSON.stringify()), making them ideal for metadata and protocol properties. Symbol.for() enables shared symbols across modules via a global registry. The well-known symbols (Symbol.iterator, Symbol.toPrimitive, Symbol.toStringTag) are the most powerful feature — implementing them on your classes lets you customize fundamental JavaScript behaviors like iteration, coercion, and type detection.
Exam Focus
Revise definitions, diagrams, examples, and short-answer points for JavaScript Symbols - Complete Guide with Well-Known Symbols.
Interview Use
Prepare one clear explanation, one practical example, and one common mistake for this JavaScript Master Course topic.
Search Terms
javascript-complete-guide, javascript master course, javascript, complete, guide, advanced, symbols, javascript symbols - complete guide with well-known symbols
Related JavaScript Master Course Topics