Introduction
Of all the new features in ES6, Symbols might be one of the most interesting to me. I've never been a Ruby developer, so I've never actually seen or used these primitive types in practice. It's an interesting concept, and I'll be diving into the essentials throughout this article.
ES6 Symbols
So, what exactly is a JavaScript symbol? It's a new unique, immutable, primitive data type introduced in ES6, originally meant to provide private properties.
var sym = Symbol();
typeof sym; // Returns "symbol"
Symbols can be used to access object properties, much like strings do:
var obj = {};
var sym = Symbol();
obj[sym] = "a";
console.log(obj[sym]); // Prints "a"
The main difference here is the property accessed by sym
does not show up in the object if iterated on, or if stringify
'd. For example:
var obj = {};
var sym = Symbol();
obj['hi'] = "bye";
obj[sym] = "a";
console.log(obj); // Prints "{hi: 'bye'}"
for (var i in obj) {
console.log(i); // Prints "hi"
}
console.log(JSON.stringify(obj)); // Prints {"hi":"bye"}
So, as you can see, the only way you can access a "symboled" property is with the original symbol object, otherwise you wouldn't even know the property exists. So this means we can use Symbols to finally have private properties in JavaScript, right? Nope. Turns out, symbols were severely downgraded from the original spec (for reasons unknown to me), and can not be used to reliably create private properties. An object's Symbols can be accessed via Object.getOwnPropertySymbols
, thus making them public for all to see.
var obj = {};
var sym = Symbol();
obj['hi'] = "bye";
obj[sym] = "a";
Object.getOwnPropertySymbols(obj); // Returns [ Symbol() ]
A word of warning, many people still believe JS symbols provide private properties to objects, so be careful what you read and believe on forums and Stack Overflow. Hopefully the misconceptions will be corrected once ES6 becomes more mainstream.
You may also see a lot of examples where the symbol is passed an optional string, like so:
var sym = Symbol("foo");
This descriptor is strictly used for debugging purposes, and does not affect the uniqueness of the symbol. To make this more clear, here is an example:
Symbol("foo") === Symbol("foo"); // Evaluates to false
var sym = Symbol("foo");
console.log(sym.toString()); // Prints "Symbol(foo)"
Global Scope
It is important to realize that using the Symbol()
function will not create a global symbol that is available in the global scope. The symbol remains specific to the object in which it is used. You can, however, create global symbols using Symbol.for()
and Symbol.keyFor()
to get and set symbols from the global symbol registry.
Symbol.for(key)
searches for existing symbols with the given key (a string) and returns it if its found. If the symbol is not found, a new one is created in the global registry with the given key and then returned.
Check out our hands-on, practical guide to learning Git, with best-practices, industry-accepted standards, and included cheat sheet. Stop Googling Git commands and actually learn it!
Symbol.for("foo"); // Creates a new global symbol
var sym = Symbol.for("foo"); // Retrieves the already created symbol
Unlike Symbol([description])
, specifying the key in Symbol.for(key)
does return the same symbol each time, so:
Symbol.for("bar") === Symbol.for("bar"); // Evaluates to true
Symbol("bar") === Symbol("bar"); // Evaluates to false
Symbol.keyFor(sym)
is essentially opposite of Symbol.for(key)
, instead of passing a key to get a symbol, you pass a symbol to get a key.
var sym = Symbol.for("foo"); // Creates new global symbol
console.log(Symbol.keyFor(sym)); // Prints "foo"
Conclusion
Although JavaScript symbols are a new and some-what interesting idea, I'm skeptical of their usefulness without the guarantee of private properties. Some people have suggested they will be good for avoiding naming conflicts, which can be helpful, but I believe their true potential won't be realized without providing truly private properties. We'll see how things progress with future updates.
What do you think of Symbols? In what ways have you found them useful? Let us know in the comments!