Javascript Do you know the Symbol type?
An introduction to the Symbol type introduced by ES2015
Among the numerous novelties that ES6 (also known as ECMAScript 2015) brought, there is one that I would say has gone quite unnoticed, especially if we compare its popularity with other features such as the spread operator or the tagged templates of which I already spoke in other articles:
As the title suggests, I am referring to the definition of the new Symbol type that comes to join the rest of the primitive types:string
, number
, boolean
, null
and undefined
. So in this article I intend to list the main characteristics of this new type as well as its main uses.
Let’s see them!
The type Symbol
First of all to understand the Symbol type is to turn to the definition made of it in the Mozilla documentation:
The data type symbol is a primitive data type. The
Symbol()
function returns a value of type symbol, has static properties that expose several members of built-in objects, has static methods that expose the global symbol registry, and resembles a built-in object class, but is incomplete as a constructor because it does not support the syntax "new Symbol()
".
To be honest, the first time I read this definition, the truth is that I stayed the same as I was, so I will add one that will give us a better idea of what the Symbol type really is:
The Symbol type allows us to obtain values that cannot be re-created, that is, they are unique and immutable identifiers.
According to this definition, the one provided by MDN makes more sense since since the values created as Symbol will be unique, we can use them to identify properties of objects.
Creating a Symbol
In the same way that we can create primitive types using factory functions (Boolean(false)
), the way in which we will create values of the Symbol type will be exactly the same:
const myFirstSymbol = Symbol();
Although we can also pass a string
to create it:
const foo = Symbol('foo');
that has no more use than to be able to identify that Symbol when we are debugging the code, since when printing it on screen we will have:
console.log(foo); // Symbol(foo);
In any case, each time we invoke the Symbol()
function we will obtain a unique identifier that will be different from any other Symbol created before or after.
For example:
Symbol() === Symbol() // false
Or for example:
const a = Symbol('a');const otherA = Symbol('a');a === otherA // false
Characteristics of the type Symbol
Among the main ones of the Symbol type we can mention the following:
- All the values of type Symbol created by the factory function
Symbol()
are unique so that they will never collide with each other. - The properties of an object whose key is a Symbol are not listed using the
Object.getOwnPropertyNames()
orObject.keys()
functions or in the loops of typefor...of
orfor...in
. - If we want to list the properties of an object whose key is a Symbol, we must use the ES6
Object.getOwnPropertySymbols()
function. - Symbol type values do not “suffer” type casting, that is, the following code would give an error:
const foo = Symbol('foo');console.log('This is the symbol foo: ' + foo); // Error
Accessing previously created Symbols
While it is true that every time we use the Symbol()
function we obtain a unique identifier, Javascript provides us with the Symbol.for(key)
method to either create a Symbol associated with the passed key, or retrieve it from the registry of Symbols
Thanks to this function, if for example we create a Symbol by assigning it a key:
const foo = Symbol.for('foo');
Later we can recover this Symbol as follows:
const bar = Symbol.for('foo');foo === bar; // true
❗❗❗ Be careful. To obtain the same symbol it is necessary to have created it using the Symbol.for
function so that the following code would result in false
:
const foo = Symbol('foo');const bar = Symbol.for('foo');foo === bar; // false
Predefined Symbols
Javascript has defined a few Symbols within the Symbol class that are used by other types to provide different features that were not accessible to developers before the arrival of ES6.
Probably the best known is Symbol.iterator
, which allows us to access the default iterator of an object:
const arr = [1, 2, 3];const iterator = arr[Symbol.iterator]();console.log(iterator.next()); // {value: 'a', done: false}
Use cases for Symbol type
Well, now that we know how to create Symbols, let’s look at some of its main uses.
Symbols as object property keys
As the Mozilla documentation mentions, the most characteristic use for the Symbol is to be used as identifiers for the properties of the objects:
const foo = Symbol();const myObject = {};myObject[foo] = 'foo';myObject['bar'] = 'bar';console.log(myObject); // {bar: "bar", Symbol(): "foo"}console.log(foo in myObject); // trueconsole.log(myObject[foo]); // 'foo'console.log(Object.getOwnPropertyNames(myObject)); // ['bar']console.log(Object.keys(myObject)); ['bar']
Since the Object.getOwnPropertyNames
and Object.keys
methods do not return the keys declared through Symbols, it might seem that another of their uses might be to allow us to declare private properties within objects; since once used the Symbol()
for a property there would be no way to recover it.
However, there are alternatives to the previous methods to enumerate the properties of objects. For example, the Reflect.ownKeys()
method of the Reflect object is capable of listing the properties declared by Symbols:
console.log(Reflect.ownKeys(myObject)); ['bar', Symbol]
Prevent collisions of property names
Another feature covered by the Symbol is the possibility that different developers or libraries add properties to objects without modifying existing ones.
For example, I can think of that problem as of 2009 that caused different libraries to overwrite the jQuery
object, leading to a multitude of failures and errors. Thanks to the Symbol, this is as simple as:
// Library Aconst jQuerySymbolA = Symbol('library a');
window[jQuerySymbolA] = $;// Library Bconst jQuerySymbolB = Symbol('library b');
window[jQuerySymbolB] = $;
In this way we will be ensuring that the jQuery object is not overwritten by other libraries and that we will always access ours.
Final thoughts
I hope to have summarized in this article the most important characteristics and use cases of the Symbol. Of course, this is only the tip of the iceberg, so from now on it is our task to familiarize ourselves with its use or find new ways to take advantage of everything they offer us.
References
Do you want to read more articles like this?
If you liked this article I encourage you to subscribe to the newsletter that I send every Sunday with similar publications to this and more recommended content: 👇👇👇