In this article, we are going to explore the JavaScript Symbol type. Moreover, we are going to answer the following questions: what is it? how to create one? what are the wrong ways to create a JavaScript Symbol? and a whole lot more.
Introduction
Symbols are the newest JavaScript primitive as of this writing. In fact, many developers aren’t aware that this feature exists, including me at first. Bringing in a new feature to a language means benefits to the language and we should understand the particular use of a certain feature. Therefore, we are going to tackle the benefits and its particular usage of JavaScript symbols. OK, then let’s get started.
Table of Contents
JavaScript Symbol is a new primitive type introduced in ES6. In addition, a symbol is a unique and immutable value. Creating a new symbol is quite easy, you just need to call the Symbol()
function which returns a unique symbol every time it is invoked. Will get into examples in later sections.
As we have described in the previous section, we said that in order to create a new JavaScript symbol, we just need to call the Symbol
function. Another thing to mention about it, symbols don’t have literal form; thus, we can only use the Symbol()
function to create one.
See the example below.
const mySymbol1 = Symbol();
const mySymbol2 = Symbol();
console.log(mySymbol1, mySymbol2);
Now, that we have seen how to create a new JavaScript Symbol. Let’s not forget that, a Symbol()
function takes an optional string parameter which represents that description of the Symbol
. Based on my experience, the description is used for debugging purposes but not to access the Symbol
itself.
See the example below:
const mySymbolWithDescription1 = Symbol("First description");
const mySymbolWithDescription2 = Symbol("Second description");
console.log(mySymbolWithDescription1, mySymbolWithDescription2);
Symbols are always 100% guaranteed to be unique. Remember, that description is just a label
that doesn't affect anything. Again, the description is just a label
nothing more nothing less.
See the example below:
const mySymbol_1 = Symbol("Cat");
const mySymbol_2 = Symbol("Cat");
console.dir(mySymbol_1 === mySymbol_2);
The first time I learned JavaScript Symbol, I thought I can create a new instance by using the Symbol()
function. Eventually, it throws an error that says: “Symbol is not a constructor”
when creating a new instance.
See the example below:
try {
const _newSymbols = new Symbol();
} catch (error) {
console.dir(error.message);
}
So, as you can see in the example above, using a new keyword to create a new instance of the Symbol
isn't going to work because based on our previous section, we have to directly invoke the Symbol()
function.
It's always been fun to use the typeof
operator. Thus, the result would be a symbol
and not an object because it is primitive.
Based on my observation, JavaScript types support implicit conversion to string
. However, Symbol
type doesn't auto-convert. You really need to explicitly call the .toString()
method.
const mySymbolType = Symbol();
console.log(typeof mySymbolType);
const mySymbolType = Symbol();
alert(mySymbolType);
const _newSymbols2 = Symbol("Hello");
console.log(_newSymbols2.toString());
console.log(_newSymbols2.description);
As of today, the JavaScript object property keys can be strings or symbols. Moreover, an object having a Symbol
type of property will not be listed when you try to enumerate the object keys. Thus, in my opinion, it looks hidden when you enumerate but not exactly when you use the []token.
See the examples below:
const customerSymbol = Symbol("Object date created");
let customer = {
name: "Jin Vincent Necesario",
[customerSymbol]: new Date()
};
console.log(customer);
Output:
for (const key in customer) {
if (customer.hasOwnProperty(key)) {
console.log(`customer.${key} is equals to ${customer[key]}`);
}
}
However, we can access that contains the symbol via []
token.
console.log("customer[customerSymbol] is equals to " + customer[customerSymbol].getFullYear());
But, of course, there's another way to access the Symbols directly by the use of Object.getOwnPropertySymbols()
method.
console.log(Object.getOwnPropertySymbols(customer));
Output:
Basically, the Symbol
object maintains a registry of the key/value, where the key is the description, and the value is the symbol. Now, when using a Symbol.for
method, it gets added to the registry and the method returns the symbol. Thus, if we try to create a symbol with an existing description, then it will be retrieved.
const mySymbolFor = Symbol.for("My Unique Description");
let product = {
name: "Toyota",
[mySymbolFor]: "Toyota Hilux G"
};
const mySymbolFor2 = Symbol.for("My Unique Description");
console.log(mySymbolFor === mySymbolFor2);
Now, you have gone this far. You might actually be getting your hands dirty with JavaScript Symbol. And, you might be asking: "What's the benefit?".
Actually, they are useful in situations where libraries want to add properties to objects without the risk of having the name collisions.
- Symbols are invoked with the use of
Symbol()
function when you try to use a new instance an error will be thrown. - JavaScript Symbols are always unique.
- Symbols descriptions are purposely for debugging and having the same description doesn't mean Symbols are equivalent.
- JavaScript Symbols should be explicitly converted into a
string
, if you wanted to. - JavaScript can be used within an object property to prevent property name collisions.
- The
Symbol.for
has a table registry for key-value pair, which retrieves existing symbol description, else creates a new one.
I hope you have enjoyed this article, as I have enjoyed writing it. Stay tuned for more. Until next time, happy programming!
- 31st July, 2020: Initial version