ES6, released in 2015, introduced a lot of features: the class
keyword, generators, const
/let
declarations and so on. But one feature that kind of went under the radar is the Symbol
data structure. In this post, I will explain what ES6 Symbols are, why you might want to use it and how it works.
The actual type is called symbol
, and Symbol()
is its constructor function. symbol
is a primitive data type. A primitive data type means that symbol
is not an object and has no methods attached to it. In addition, primitive data types have one more property that is important: immutability. Observe the difference between primitive and complex data types:
What do ES6 Symbols do?
The main purpose of ES6 Symbols is to return unique values. That is it. You pass in a human-readable name to the symbol constructor and it returns a unique value that can be used elsewhere. In fact, these values are so unique that it can be confusing:
You never use the symbol value directly, nor there is an easy way to do so. If you want to access the same symbol elsewhere in the codebase, you can use Symbol.for()
:
Symbol.for()
accepts a key for a symbol and tries to get this symbol from the global symbol registry. If not found, it will create one, store it and return. You can imagine it to be working like this (very simplified version):
What are ES6 Symbols used for?
The most popular use-case for symbols is to use them as object properties. Their advantage is that such properties do not show up in the property enumeration (e.g. for..of
loop), which makes them perfect for meta-programming and defining hidden/internal methods of objects.
Symbols are being used already by most JS engines internally, hence the meta-programming feature. For example, iterable objects have a Symbol.iterator
function that is used by for..of
loops. Objects that can be cast to primitives (String
, Number
, etc.) have a Symbol.toPrimitive
function that does so. Here is a full list of them:
What are ES6 Symbols not used for?
It is also very important to understand what symbols cannot do, as it gets kind of confusing here. My first example is going to be about Redux, so if you are not familiar with it, you can skip to the next paragraph. Now, it might be tempting to use symbols as action types in your redux action creators. It was my first thought as well, but there is a very good argument that symbols are not fit for it. The reason is that symbols are not serializable and there is no way (yet) to save them to the storage, or send to another entity. Thus, replay, persistence, and even debugging would simply not work if you use symbols as types for your redux actions. You can follow this discussion to find out more.
Symbols are also not a way to define private object properties. Even though these properties will not show up in regular enumeration, you can still access them with Object.getOwnPropertySymbols
. We are still waiting for truly private properties and this proposal may just be it.
Thank you for reading this article, I hope you found it useful. Please feel free to share your thoughts or correct me in the comments.
one comment