Q23 of 40 · JavaScript
What is the `Symbol` type in JavaScript, and when is it useful?
Short answer
Short answer: Symbol creates a guaranteed-unique primitive — every `Symbol()` call produces a value unequal to any other. Symbols are non-enumerable in for-in and JSON.stringify. Use cases: unique object keys that avoid collisions, well-known symbols (Symbol.iterator) to customise built-in behaviour, and cross-realm shared keys via Symbol.for.
Detail
Symbols are the seventh primitive type added in ES6. The key guarantee is uniqueness: Symbol('x') !== Symbol('x') — even two Symbols with the same description are distinct values.
Creating symbols: Symbol(description) creates a local unique symbol. Symbol.for(key) creates/retrieves a symbol from a global registry — two calls with the same key return the exact same symbol, even across modules or iframes.
Non-enumerable metadata keys: Adding a Symbol-keyed property to an object prevents it appearing in for...in, Object.keys(), or JSON.stringify(). It does appear in Object.getOwnPropertySymbols() and Reflect.ownKeys(). Useful for attaching metadata without polluting the visible interface.
Well-known Symbols: The spec defines built-in symbols on the Symbol object that customise built-in behaviours:
Symbol.iterator: makes an object iterable (for...of)Symbol.toPrimitive: controls type coercionSymbol.hasInstance: customisesinstanceof
In testing: Symbols occasionally appear in frameworks using them for internal tagging (React's Symbol.for('react.element')). Understanding them prevents confusion when inspecting framework-internal objects in tests.
// EXAMPLE
const id = Symbol("id");
const user = { name: "Alice", [id]: 123 };
console.log(user[id]); // 123
console.log(Object.keys(user)); // ["name"] — symbol not visible
console.log(JSON.stringify(user)); // '{"name":"Alice"}' — symbol dropped
// Symbol.for — global registry
const s1 = Symbol.for("shared");
const s2 = Symbol.for("shared");
console.log(s1 === s2); // true
// Well-known symbol: custom iterable
class Range {
constructor(start, end) { this.start = start; this.end = end; }
[Symbol.iterator]() {
let cur = this.start, end = this.end;
return { next() {
return cur <= end ? { value: cur++, done: false } : { done: true };
}};
}
}
console.log([...new Range(1, 4)]); // [1, 2, 3, 4]