Q23 of 40 · JavaScript

What is the `Symbol` type in JavaScript, and when is it useful?

JavaScriptMidjavascriptsymboles6primitivesiterators

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 coercion
  • Symbol.hasInstance: customises instanceof

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]

// WHAT INTERVIEWERS LOOK FOR

The uniqueness guarantee and why it differs from string keys. Non-enumerability and JSON visibility. Well-known symbols as extension points. Most candidates haven't used Symbol deeply — demonstrating this knowledge shows thoroughness.

// COMMON PITFALL

Thinking `Symbol.for('x') === Symbol('x')` — they are not equal. `Symbol.for` uses a global registry; `Symbol()` always creates a new unique value regardless of the description.