Skip to content

Symbol

Symbol is a primitive data type introduced in ES6 (2015) that creates unique, immutable values. Symbols are often used as property keys to avoid name collisions.

Used strings or conventions to avoid collisions:

// String properties can collide
const obj = {};
obj.id = 1;
// ... later, someone else
obj.id = 2; // Overwrites!
// Naming conventions (not guaranteed unique)
obj._privateId = 1;
obj.__id = 2;

Symbols guarantee uniqueness:

// Create unique symbols
const id1 = Symbol();
const id2 = Symbol();
console.log(id1 === id2); // false - each symbol is unique
// Symbols with descriptions (for debugging)
const userId = Symbol('userId');
const userName = Symbol('userName');
console.log(userId.toString()); // "Symbol(userId)"
// Use as object properties
const user = {};
const ID = Symbol('id');
user[ID] = 12345;
user.id = "ABC"; // Different property
console.log(user[ID]); // 12345
console.log(user.id); // "ABC"
// Symbols in object literals
const EMAIL = Symbol('email');
const person = {
name: "Alice",
[EMAIL]: "alice@example.com"
};
// Symbol.for() - global symbol registry
const sym1 = Symbol.for('app.id');
const sym2 = Symbol.for('app.id');
console.log(sym1 === sym2); // true - same symbol from registry
// Symbol.keyFor() - get key from registry
console.log(Symbol.keyFor(sym1)); // "app.id"
// Well-known symbols (built-in)
const arr = [1, 2, 3];
console.log(arr[Symbol.iterator]); // [Function: values]
// Custom iterator
const obj = {
values: [1, 2, 3],
[Symbol.iterator]() {
let index = 0;
return {
next: () => ({
value: this.values[index++],
done: index > this.values.length
})
};
}
};
for (const val of obj) {
console.log(val); // 1, 2, 3
}
  • Uniqueness: Each symbol is guaranteed unique
  • No collisions: Safe property keys
  • Hidden: Symbols don’t appear in for...in or Object.keys()
  • Well-known symbols: Customize language behaviors
  • Type safety: Can’t accidentally create same symbol
  • Symbols are not strings (can’t use in template literals directly)
  • Not included in Object.keys(), Object.entries(), JSON.stringify()
  • Included in Object.getOwnPropertySymbols()
  • Included in Reflect.ownKeys()
  • Symbol('desc')Symbol('desc') (different symbols)
  • Symbol.for('key') === Symbol.for('key') (same from registry)
// Symbols are hidden from normal iteration
const ID = Symbol('id');
const obj = {
name: "Alice",
[ID]: 123
};
console.log(Object.keys(obj)); // ["name"]
console.log(Object.getOwnPropertySymbols(obj)); // [Symbol(id)]
console.log(Reflect.ownKeys(obj)); // ["name", Symbol(id)]
// Not stringifiable
JSON.stringify(obj); // {"name":"Alice"} - symbol property ignored
// Can't use in template literal
const sym = Symbol('test');
console.log(`Value: ${sym}`); // TypeError
// Use .toString() or .description
console.log(sym.toString()); // "Symbol(test)"
console.log(sym.description); // "test"
// Well-known symbols
const obj = {
[Symbol.toStringTag]: 'CustomObject'
};
console.log(obj.toString()); // "[object CustomObject]"
  1. Create a unique symbol for a private property

    Answer
    const privateKey = Symbol('private');
    const obj = {
    [privateKey]: "secret value"
    };
  2. What’s the difference between Symbol() and Symbol.for()?

    Answer `Symbol()` creates a new unique symbol each time. `Symbol.for(key)` uses a global registry - same key returns same symbol.
  3. Are symbols included in Object.keys()?

    Answer No. Use `Object.getOwnPropertySymbols()` or `Reflect.ownKeys()` to get symbol properties.