Symbol – Creating Unique Identifiers
With the introduction of ES6 (ECMAScript 2015), JavaScript introduced a new primitive data type: the Symbol. Symbols serve as unique identifiers and allow developers to create properties that are guaranteed to be unique. In this article, we will explain the use of Symbols, show their advantages, and demonstrate with practical code examples how they can be used in modern JavaScript applications.
What is a Symbol?
A Symbol is a primitive data type, similar to Number, String, Boolean, Null, and Undefined. Each Symbol is unique and can be used as a unique key for object properties. This helps avoid name conflicts and allows the creation of properties that cannot be accidentally overwritten.
Creating a Symbol:
const mySymbol = Symbol();
Properties of Symbols
-
Uniqueness: Each Symbol is unique. Even if two Symbols are created with the same description string, they are not equal.
const sym1 = Symbol('id'); const sym2 = Symbol('id'); console.log(sym1 === sym2); // false -
Not automatically iterable: Symbols are not considered in iterations like
for...inorObject.keys(). This allows properties to be hidden.
Using Symbols as Object Keys
Symbols are excellent as keys for object properties, especially when you want to prevent these properties from being accidentally overwritten or manipulated from outside.
Example:
const UNIQUE_ID = Symbol('id');
const user = {
name: 'Max',
[UNIQUE_ID]: 12345
};
console.log(user[UNIQUE_ID]); // 12345
console.log(user.UNIQUE_ID); // undefined
Well-Known Symbols
JavaScript provides several built-in Symbols for special purposes, called “Well-Known Symbols”:
Symbol.iterator:
const iterable = {
[Symbol.iterator]() {
let step = 0;
return {
next() {
step++;
if (step <= 3) {
return { value: step, done: false };
}
return { value: undefined, done: true };
}
};
}
};
for (let value of iterable) {
console.log(value); // 1, 2, 3
}
Symbol.toStringTag:
class MyClass {
get [Symbol.toStringTag]() {
return 'MyClass';
}
}
const obj = new MyClass();
console.log(Object.prototype.toString.call(obj)); // [object MyClass]
Practical Use Cases
1. Private Properties:
const _private = Symbol('private');
class MyClass {
constructor() {
this[_private] = 'secret data';
}
getPrivate() {
return this[_private];
}
}
const instance = new MyClass();
console.log(instance.getPrivate()); // secret data
console.log(instance[_private]); // undefined (not accessible from outside)
2. Avoiding Name Collisions:
const lib1 = {
[Symbol('id')]: 1
};
const lib2 = {
[Symbol('id')]: 2
};
// No collision, each Symbol is unique
3. Global Symbol Registry:
const globalSym1 = Symbol.for('app.id');
const globalSym2 = Symbol.for('app.id');
console.log(globalSym1 === globalSym2); // true
console.log(Symbol.keyFor(globalSym1)); // 'app.id'
Conclusion
Symbols are a valuable addition to JavaScript that enable unique identifiers and help avoid name conflicts. They are particularly useful for creating private properties, implementing custom iteration behavior, and working with meta-programming. While they are an advanced feature, understanding and using Symbols can significantly enhance your JavaScript development.
Use Symbols in your next project and discover how they can help create more robust and maintainable code!