10-ES6++: Symbols
Hasan Zohdy
Posted on November 19, 2022
Symbols
In ES6 we have a new primitive data type called symbol
. Symbols are used to create unique identifiers
for objects. We can also use symbols to create private properties and methods in objects, but let's first see how to create symbols.
Creating symbols
To create a symbol, we use the Symbol()
function.
const symbol = Symbol();
The Symbol()
function can take an optional description
parameter, which is used to describe the symbol.
const missingKey = Symbol("missingKey");
The description
parameter is used to describe the symbol, it's not used to set the value of the symbol.
Uniqueness of symbols
In that sense, we can conclude that every symbol is unique, even if they have the same description.
Let's see an example
const symbol1 = Symbol("symbol");
const symbol2 = Symbol("symbol");
console.log(symbol1 === symbol2); // false
Same exact description but they are different, how is that possible? let me explain.
Each time the Symbol
function is called (BTW it can not be instantiated with new keyword, you can not do new Symbol
), it returns a new symbol, that symbol is guaranteed to be unique during
, it is stored in a global symbol registry
to make sure it's unique.
When to use symbols
Symbols have really really useful use cases, they can be used in:
- Object Properties
- Object methods
- Object iterators
- Object generators
- Object async generators
Let's see an example for each use case of the above list.
Object Properties
We can use symbols to create private properties in objects.
const person = {
name: "Hasan",
age: 30,
city: "Cairo",
[Symbol("secret")]: "MySecret",
};
console.log(person); // { name: 'Hasan', age: 30, city: 'Cairo' }
As you can see, the secret
property is not visible in the console, because it's a private property.
Object methods
We can also use symbols to create private methods in objects.
const isAdult = Symbol("isAdult");
const person = {
name: "Hasan",
age: 30,
city: "Cairo",
[isAdult]() {
return this.age >= 18;
},
canVote() {
if (this[isAdult]()) {
console.log("You can vote");
} else {
console.log("You can not vote");
}
},
};
person.canVote(); // You can vote
So we've here created some sort of a private
method called isAdult
, and we used it in the canVote
method, this will make sure that this method is not accessible from outside the object.
Object iterators
We can also use symbols to create iterators for objects.
const person = {
name: "Hasan",
age: 30,
city: "Cairo",
// iterate and return key, value pairs
[Symbol.iterator]() {
const keys = Object.keys(this);
let index = 0;
return {
next: () => {
if (index < keys.length) {
const key = keys[index];
const value = this[key];
index++;
return {
value: [key, value],
done: false,
};
} else {
return {
done: true,
};
}
},
};
},
};
for (const [key, value] of person) {
console.log(key, value); // name Hasan age 30 city Cairo
}
That one of the most important ways to use in your class/object to perform iteration over it.
Object generators
We can also use symbols to create generators for objects.
const person = {
name: "Hasan",
age: 30,
city: "Cairo",
// iterate and return key, value pairs
*[Symbol.iterator]() {
const keys = Object.keys(this);
for (const key of keys) {
yield [key, this[key]];
}
},
};
for (const [key, value] of person) {
console.log(key, value); // name Hasan age 30 city Cairo
}
Object async generators
We can also use symbols to create async generators for objects.
const person = {
name: "Hasan",
age: 30,
city: "Cairo",
// iterate and return key, value pairs
async *[Symbol.asyncIterator]() {
const keys = Object.keys(this);
for (const key of keys) {
yield [key, this[key]];
}
},
};
(async () => {
for await (const [key, value] of person) {
console.log(key, value); // name Hasan age 30 city Cairo
}
})();
Symbol.for()
The Symbol.for(key)
method searches for existing symbols in the symbol registry with the given key and returns it if found. Otherwise a new symbol gets created in the global symbol registry with this key.
const symbol1 = Symbol.for("symbol");
const symbol2 = Symbol.for("symbol");
console.log(symbol1 === symbol2); // true
As you can see, the symbols are the same, because they are stored in the global symbol registry.
So if we want to control the value of a symbol, we should use Symbol.for()
, but it is not recommended
to use it most of the time, because it can cause some problems.
Symbol.keyFor()
The Symbol.keyFor(symbol)
method returns a shared symbol key from the global symbol registry for the given symbol.
const symbol1 = Symbol.for("MySymbolKey");
// now using keyFor method
const key = Symbol.keyFor(symbol1);
console.log(key); // MySymbolKey
This won't work with does not have a key, it will return undefined if you used it with Symbol
function for example.
const symbol1 = Symbol("MySymbolKey");
// now using keyFor method
const key = Symbol.keyFor(symbol1);
console.log(key); // undefined
🎨 Conclusion
In this article, we've learned about symbols, how to create them, how to manually set symbol key and how to retrieve that key, and how to use them properly.
☕♨️ Buy me a Coffee ♨️☕
If you enjoy my articles and see it useful to you, you may buy me a coffee, it will help me to keep going and keep creating more content.
😍 Join our community
Join our community on Discord to get help and support (Node Js 2023 Channel).
📚 Bonus Content 📚
You may have a look at these articles, it will definitely boost your knowledge and productivity.
General Topics
- Event Driven Architecture: A Practical Guide in Javascript
- Best Practices For Case Styles: Camel, Pascal, Snake, and Kebab Case In Node And Javascript
- After 6 years of practicing MongoDB, Here are my thoughts on MongoDB vs MySQL
Packages & Libraries
- Collections: Your ultimate Javascript Arrays Manager
- Supportive Is: an elegant utility to check types of values in JavaScript
- Localization: An agnostic i18n package to manage localization in your project
React Js Packages
Courses (Articles)
Posted on November 19, 2022
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.