ES6, released in 2015, introduced a lot of features: the
class keyword, generators,
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 them and how they work.
The actual type is called
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() 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 (
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.