In JavaScript, Symbol
is a primitive data type introduced in ES6 (ECMAScript 2015) that generates a unique and immutable value. Symbols are often used to create unique identifiers for object properties, ensuring that there are no naming conflicts, especially when working with libraries or large codebases.
Creating and Using Symbols
To create a symbol, you use the Symbol()
function. Each time you call Symbol()
, it generates a new, unique symbol, even if you pass the same description.
I. Creating a Symbol
let symbol1 = Symbol();
let symbol2 = Symbol('description');
let symbol3 = Symbol('description');
console.log(symbol2 === symbol3); // false
Despite symbol2
and symbol3
having the same description, they are different and unique.
II. Using Symbols
Symbols are often used as keys for object properties. The uniqueness of symbols ensures that property keys do not clash with other keys in the object, including keys added by extensions or libraries.
let id = Symbol('id');
let user = {
name: 'John Doe',
[id]: 123 // Symbol as a property key
};
console.log(user[id]); // 123
Symbols in Object Properties and Their Uses
Symbols bring several benefits when used as object properties:
I. Privacy
Symbols are not enumerable in for…in loops and do not show up in Object.keys()
or JSON.stringify()
, providing a form of property privacy.
for (let key in user) console.log(key); // name
console.log(Object.keys(user)); // ['name']
console.log(JSON.stringify(user)); // {"name":"John Doe"}
This makes symbols ideal for adding metadata or non-enumerable properties to objects that should not be directly accessed or altered.
II. Avoiding Property Name Collisions
Using symbols as property keys helps avoid naming collisions, especially in larger applications or when integrating with third-party libraries.
III. Well-Known Symbols
JavaScript defines several well-known symbols with predefined behaviors. For example, Symbol.iterator
defines the default iterator for an object.
let iterable = {
[Symbol.iterator]() {
let step = 0;
return {
next() {
step++;
if (step === 1) return { value: 'Hello', done: false };
else if (step === 2) return { value: 'World', done: false };
return { value: undefined, done: true };
}
};
}
};
for (let value of iterable) {
console.log(value); // "Hello" then "World"
}
This allows customization of iteration logic for custom objects.
IV. Symbol.for and Symbol.keyFor
Symbol.for(key)
searches for existing symbols with the given key in the global symbol registry and returns it if found. Otherwise, it creates a new global symbol.
let globalSymbol = Symbol.for('globalSymbol');
let sameGlobalSymbol = Symbol.for('globalSymbol');
console.log(globalSymbol === sameGlobalSymbol); // true
Symbol.keyFor(symbol)
retrieves a shared symbol’s key from the global symbol registry.
console.log(Symbol.keyFor(globalSymbol)); // 'globalSymbol'
Conclusion
Symbols offer a powerful way to create unique and hidden properties on objects, ensuring that your codebase remains conflict-free and maintainable. By leveraging symbols for private properties or integrating well-known symbols, you can enhance functionality and ensure compatibility across different parts of your applications.