Symbols are unique, immutable identifiers. They solve real problems like property collision and protocol implementation.
Creating Symbols
const sym1 = Symbol("description");
const sym2 = Symbol("description");
sym1 === sym2; // false! Every Symbol is unique
// Global symbols (shared across realms)
const globalSym = Symbol.for("app.config");
Symbol.for("app.config") === globalSym; // trueUse Case 1: Collision-Free Property Keys
// Library code — guaranteed no collision with user properties
const INTERNAL_STATE = Symbol("internalState");
const VALIDATOR = Symbol("validator");
class Form {
[INTERNAL_STATE] = { dirty: false, submitted: false };
[VALIDATOR] = null;
setValidator(fn) { this[VALIDATOR] = fn; }
submit() {
this[INTERNAL_STATE].submitted = true;
if (this[VALIDATOR]) this[VALIDATOR](this.data);
}
}
// User can't accidentally overwrite internal state
const form = new Form();
form.internalState; // undefined (not the same property!)Use Case 2: Well-Known Symbols
// Symbol.iterator — make objects iterable
class Range {
constructor(start, end) {
this.start = start;
this.end = end;
}
[Symbol.iterator]() {
let current = this.start;
const end = this.end;
return {
next() {
return current <= end
? { value: current++, done: false }
: { done: true };
}
};
}
}
for (const n of new Range(1, 5)) console.log(n); // 1, 2, 3, 4, 5
[...new Range(1, 3)]; // [1, 2, 3]Symbol.toPrimitive
class Money {
constructor(amount, currency) {
this.amount = amount;
this.currency = currency;
}
[Symbol.toPrimitive](hint) {
if (hint === "number") return this.amount;
if (hint === "string") return `${this.amount} ${this.currency}`;
return this.amount;
}
}
const price = new Money(42, "USD");
+price; // 42
`${price}`; // "42 USD"Symbol Properties Are Hidden
const obj = { [Symbol("secret")]: "hidden", visible: "shown" };
Object.keys(obj); // ["visible"]
JSON.stringify(obj); // {"visible":"shown"}
Object.getOwnPropertySymbols(obj); // [Symbol(secret)]When to Use Symbols
- Library/framework internal properties
- Implementing protocols (iterator, toPrimitive)
- Enum-like constants that are guaranteed unique
- Metadata that shouldn't appear in serialization