JavaScript Symbol
In JavaScript, Symbols are a relatively recent addition that provide a unique and immutable primitive value. They are primarily used to create unique property keys for objects. Symbols can help avoid naming collisions and are ideal when you want to create private properties in objects. This blog post will walk you through the basics of JavaScript Symbols, their syntax, use cases, and how to work with them effectively.
A Symbol is a primitive data type introduced in ECMAScript 6 (ES6). Each Symbol is guaranteed to be unique, even if two Symbols are created with the same description. They are often used to create unique keys for object properties, ensuring that property names do not conflict with others in objects.
let sym = Symbol();
This creates a new unique Symbol that can be used as a property key for objects.
A Symbol is created by calling the Symbol()
function. Optionally, you can pass a description to the symbol. This description is mainly used for debugging purposes and does not affect the uniqueness of the Symbol.
let symbol1 = Symbol();
let symbol2 = Symbol('description');
console.log(symbol1); // Output: Symbol()
console.log(symbol2); // Output: Symbol(description)
Explanation:
symbol1
is a symbol with no description, while symbol2
has the description 'description'
.symbol1
and symbol2
are still distinct and unique.One of the most common uses of Symbols is to create unique keys for object properties. Since Symbols are unique, you can ensure there are no collisions between object properties even if other code is using the same property name.
let sym1 = Symbol('name');
let sym2 = Symbol('age');
let person = {
[sym1]: 'John Doe',
[sym2]: 30
};
console.log(person[sym1]); // Output: John Doe
console.log(person[sym2]); // Output: 30
Explanation:
sym1
and sym2
are unique symbols used as keys in the person
object.Symbols are not enumerable in for...in
loops or Object.keys()
methods. This means that you cannot accidentally access them when iterating over an object's properties using these methods. They are mainly used to add "private" properties to objects that are not directly accessible unless you explicitly reference the Symbol.
let symbol1 = Symbol('id');
let symbol2 = Symbol('id');
let user = {
[symbol1]: 1234,
[symbol2]: 5678,
name: "Alice"
};
for (let key in user) {
console.log(key); // Output: name (symbol properties are not logged)
}
console.log(Object.keys(user)); // Output: ['name'] (symbol properties are not included)
Explanation:
for...in
loop and Object.keys()
only include the regular properties, excluding Symbol-based properties.Symbol.for()
MethodIn addition to creating individual Symbols, JavaScript provides a global registry of Symbols. This registry allows you to reuse Symbols by their description across different parts of your program.
Symbol.for()
MethodThe Symbol.for()
method checks if a Symbol with a given description exists in the global registry. If it does, it returns the existing Symbol; if not, it creates a new Symbol.
Symbol.for()
let globalSymbol1 = Symbol.for('uniqueSymbol');
let globalSymbol2 = Symbol.for('uniqueSymbol');
console.log(globalSymbol1 === globalSymbol2); // Output: true
Explanation:
Symbol.for('uniqueSymbol')
creates a globally unique Symbol. Even though you create it in different places, it will always refer to the same Symbol if the description is the same.globalSymbol1
and globalSymbol2
refer to the same global Symbol because they share the same description 'uniqueSymbol'
.You can retrieve the description of a Symbol using the description
property. This is useful for debugging or logging purposes, as Symbols themselves do not convert to strings directly.
let symbol = Symbol('mySymbol');
console.log(symbol.description); // Output: mySymbol
Explanation:
description
property gives you the human-readable description passed when creating the Symbol, but the Symbol itself remains unique and cannot be directly used as a string.JavaScript also provides several built-in "well-known" Symbols that have specific behavior in the language. These Symbols allow you to customize certain operations like object iteration, type conversion, and more.
Some examples of well-known Symbols include:
Symbol.iterator
: Used to define the default iterator for an object (enables for...of
loop).Symbol.toStringTag
: Used to define the string description of an object when Object.prototype.toString()
is called.Symbol.hasInstance
: Determines if an object is an instance of a class (used in instanceof
).Symbol.iterator
let iterable = {
items: ['a', 'b', 'c'],
[Symbol.iterator]: function() {
let index = 0;
let items = this.items;
return {
next: function() {
if (index < items.length) {
return { value: items[index++], done: false };
} else {
return { value: undefined, done: true };
}
}
};
}
};
for (let item of iterable) {
console.log(item); // Output: a, b, c
}
Explanation:
iterable
uses Symbol.iterator
to define how it should be iterated over in a for...of
loop.next()
method controls the iteration and provides the values to be accessed.Symbol.for()
should be used when you need to ensure consistency across different parts of your codebase.Symbol.iterator
to enhance the behavior of objects and customize built-in JavaScript operations.