What are `Symbol`s used for in JavaScript?
TL;DR
Symbols are primitive values commonly used as collision-resistant object property keys and protocol hooks such as Symbol.iterator. Each call to Symbol(description) creates a distinct value, while Symbol.for(key) uses a shared registry. Symbol-keyed properties are skipped by for...in, Object.keys(), and JSON serialization, but they are not private: code can retrieve them with Object.getOwnPropertySymbols() or Reflect.ownKeys().
let sym1 = Symbol();let sym2 = Symbol('myKey');console.log(typeof sym1); // "symbol"console.log(sym1 === sym2); // false, because each symbol is uniquelet obj = {};let sym = Symbol('uniqueKey');obj[sym] = 'value';console.log(obj[sym]); // "value"
Note: The Symbol() function must be called without the new keyword. It is not exactly a constructor because it can only be called as a function instead of with new Symbol().
Symbols in JavaScript
Symbols in JavaScript are a unique and immutable data type used primarily for object property keys to avoid name collisions.
Key characteristics
- Uniqueness: Each
Symbolvalue is unique, even if they have the same description. - Immutability:
Symbolvalues are immutable, meaning their value cannot be changed. - Non-enumerable:
Symbolproperties are not included infor...inloops orObject.keys().
Creating Symbols
Symbols can be created using the Symbol() function:
const sym1 = Symbol();const sym2 = Symbol('uniqueKey');console.log(typeof sym1); // "symbol"console.log(sym1 === sym2); // false, because each symbol is unique
The
Symbol(..)function must be called without thenewkeyword.
Using Symbols as object property keys
Symbols can be used to add properties to an object without risk of name collision:
const obj = {};const sym = Symbol('uniqueKey');obj[sym] = 'value';console.log(obj[sym]); // "value"
Symbols are not enumerable
Symbolproperties are not included infor...inloops orObject.keys().- This can hide implementation details from ordinary string-key iteration, but it does not provide privacy.
- Use
Object.getOwnPropertySymbols(obj)to get all symbol properties on an object.
const mySymbol = Symbol('privateProperty');const obj = {name: 'John',[mySymbol]: 42,};console.log(Object.keys(obj)); // Output: ['name']console.log(obj[mySymbol]); // Output: 42
Global Symbol registry
You can create global Symbols using Symbol.for('key'), which creates a new Symbol in the global registry if it doesn't exist, or returns the existing one. This allows you to reuse Symbols across different parts of your code base or even across different code bases.
const globalSym1 = Symbol.for('globalKey');const globalSym2 = Symbol.for('globalKey');console.log(globalSym1 === globalSym2); // trueconst key = Symbol.keyFor(globalSym1);console.log(key); // "globalKey"
Well-known Symbols
JavaScript includes several built-in Symbols, referred to as well-known Symbols.
Symbol.iterator: Defines the defaultiteratorfor an object.Symbol.toStringTag: Used to create a string description for an object.Symbol.hasInstance: Used to determine if an object is an instance of a constructor.
Symbol.iterator
let iterable = {[Symbol.iterator]() {let step = 0;return {next() {step++;if (step <= 5) {return { value: step, done: false };}return { done: true };},};},};for (let value of iterable) {console.log(value); // 1, 2, 3, 4, 5}
Symbol.toStringTag
let myObj = {[Symbol.toStringTag]: 'MyCustomObject',};console.log(Object.prototype.toString.call(myObj)); // "[object MyCustomObject]"
Summary
Symbols are useful for collision-resistant object properties and for customizing built-in protocols. Symbol-keyed properties are not necessarily non-enumerable—their property descriptor can have enumerable: true—but string-key enumeration APIs still skip them. Use class #private fields or closures when true access control is required.
Further reading
- Symbol - MDN
- Symbol type
- A quick overview of JavaScript symbols
- Symbol Values - You Don't Know JS Yet