Symbols & Well-Known Symbols
Guaranteed-unique keys that never collide -- and the hooks that let objects customise built-in behaviour.
const s = Symbol('desc');
obj[Symbol.iterator] = function* () {};
Symbol.for('shared')A Symbol is a primitive whose whole purpose is uniqueness. Every Symbol('desc') is distinct from every other, even with the same description. As object keys they never clash with string keys or with each other, which makes them ideal for metadata and library-internal fields.
const id = Symbol('id');
obj[id] = 123; // invisible to for...in, JSON, Object.keysWell-known symbols: hooks into the language
Certain symbols let your objects plug into built-in operations:
Symbol.iterator-- makes an object work withfor...ofand spread.Symbol.asyncIterator-- powersfor await...of.Symbol.toPrimitive-- controls how an object coerces to number/string.Symbol.hasInstance-- customisesinstanceof.
Global registry
Symbol.for('key') returns the same symbol across your whole program (and across realms), useful for shared protocol keys.
Example
When to use it
- Use Symbol as a unique property key on an object to avoid key collisions with library or user code.
- Define a custom iterator on a class using Symbol.iterator so instances work with for-of loops.
- Use a Symbol as a private-ish identifier for an internal property that library consumers should not rely on.
More examples
Symbol as unique key
Uses a computed Symbol key so the internal id property is inaccessible by the plain string 'id'.
const id = Symbol("id");
const user = { name: "Alice", [id]: 42 };
console.log(user[id]); // 42
console.log(user.id); // undefined – not accessible by stringWell-known Symbol.iterator
Implements Symbol.iterator on a custom class so its instances are iterable with for-of and spread.
class Range {
constructor(start, end) { this.start = start; this.end = end; }
[Symbol.iterator]() {
let current = this.start;
const end = this.end;
return { next: () => current <= end
? { value: current++, done: false }
: { done: true } };
}
}
console.log([...new Range(1, 4)]); // [1, 2, 3, 4]Global symbol registry
Symbol.for creates or retrieves a shared symbol from the global registry; local Symbol() always creates a new unique one.
const s1 = Symbol.for("app.token");
const s2 = Symbol.for("app.token");
console.log(s1 === s2); // true – same global symbol
const local = Symbol("app.token");
console.log(s1 === local); // false – different
Discussion