Symbol
Symbol
Section titled “Symbol”What it is
Section titled “What it is”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.
Before this feature
Section titled “Before this feature”Used strings or conventions to avoid collisions:
// String properties can collideconst obj = {};obj.id = 1;// ... later, someone elseobj.id = 2; // Overwrites!
// Naming conventions (not guaranteed unique)obj._privateId = 1;obj.__id = 2;After this feature
Section titled “After this feature”Symbols guarantee uniqueness:
// Create unique symbolsconst 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 propertiesconst user = {};const ID = Symbol('id');user[ID] = 12345;user.id = "ABC"; // Different property
console.log(user[ID]); // 12345console.log(user.id); // "ABC"
// Symbols in object literalsconst EMAIL = Symbol('email');const person = { name: "Alice", [EMAIL]: "alice@example.com"};
// Symbol.for() - global symbol registryconst 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 registryconsole.log(Symbol.keyFor(sym1)); // "app.id"
// Well-known symbols (built-in)const arr = [1, 2, 3];console.log(arr[Symbol.iterator]); // [Function: values]
// Custom iteratorconst 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}Why this is better
Section titled “Why this is better”- Uniqueness: Each symbol is guaranteed unique
- No collisions: Safe property keys
- Hidden: Symbols don’t appear in
for...inorObject.keys() - Well-known symbols: Customize language behaviors
- Type safety: Can’t accidentally create same symbol
Key notes / edge cases
Section titled “Key notes / edge cases”- 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 iterationconst 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 stringifiableJSON.stringify(obj); // {"name":"Alice"} - symbol property ignored
// Can't use in template literalconst sym = Symbol('test');console.log(`Value: ${sym}`); // TypeError
// Use .toString() or .descriptionconsole.log(sym.toString()); // "Symbol(test)"console.log(sym.description); // "test"
// Well-known symbolsconst obj = { [Symbol.toStringTag]: 'CustomObject'};console.log(obj.toString()); // "[object CustomObject]"Quick practice
Section titled “Quick practice”-
Create a unique symbol for a private property
Answer
const privateKey = Symbol('private');const obj = {[privateKey]: "secret value"}; -
What’s the difference between
Symbol()andSymbol.for()?Answer
`Symbol()` creates a new unique symbol each time. `Symbol.for(key)` uses a global registry - same key returns same symbol. -
Are symbols included in
Object.keys()?Answer
No. Use `Object.getOwnPropertySymbols()` or `Reflect.ownKeys()` to get symbol properties.