ES6 Symbol

This is the part of a series of blogs on the new features on the upcoming ECMAScript 6 (ES6) specification which JavaScript implements.

In this blog we focus on the Symbol data type introduced in ES6.

 Symbol

We initialize a new Symbol in an almost primitive fashion, not by using a constructor, but by using its special constructor which takes in either nothing, a String, or another Symbol.

let lockhartBrain = Symbol(); // Symbol()
let harry = Symbol('harry'); // Symbol(harry)
let potter = new Symbol(harry); // Symbol(Symbol(harry))
let hermione = new Symbol('granger'); // TypeError: Symbol is not a constructor

And no Symbols are not just Strings…

assert(typeof harry === 'symbol');
let harrypotter = harry + ' potter'; // TypeError: Cannot convert a Symbol value to a string
let harrypotter = harry.toString() + ' potter'; // "Symbol(harry) potter"

For example, Symbols do not show up on an Object when you use the native for in, for of, or Object.getOwnPropertyNames.

let harry = Symbol('harry');  
let hogwarts = {};  
hogwarts['draco'] = 'malfoy';  
hogwarts[harry] = 'potter';  
Object.keys(hogwarts); // [ 'draco' ]  
Object.getOwnPropertyNames(hogwarts); // [ 'draco' ]  

So the only way to get the Symbols within an Object is by using Object.getOwnPropertySymbols.

Object.getOwnPropertySymbols(hogwarts); // [ Symbol(harry) ]
assert(Object.getOwnPropertySymbols(hogwarts)[0] === harry); 

The Symbol data type is completely unique in a sense that no two symbols share the same value under the hood of the JavaScript engine.

assert.notEqual(Symbol('weasley'), Symbol('weasley'));

 Global Symbols

What about cross application sharing? Since we have one consolidated symbol registry, we can actually only use one instance of the symbol under the hood. Meaning, a symbol in an iframe will have the same value as the symbol in the current document. To expose it, we will need to use the Symbol.for() method to reuse a symbol.

let iframe = document.getElementById('hogwarts-iframe');  
assert.notEqual(iframe.contentWindow.Symbol, Symbol);  
assert(iframe.contentWindow.Symbol.for('harry') === Symbol.for('harry'));

So we know there are both local and global symbols (by using the Symbol.for method) but how can we differentiate them? ES6 has got you on that with the method Symbol.keyFor() which exposes the string used for creating the global symbol.

let localHarry = Symbol('harry');  
let globalHarry = Symbol.for('harry');
assert(Symbol.keyFor(localHarry) === undefined);
assert(Symbol.keyFor(globalHarry) === 'harry');
assert(Symbol.for(Symbol.keyFor(globalHarry)) === Symbol.for('harry'));

 Use Cases

Symbols are guaranteed to never conflict as an object key if you are using it locally.

Symbols cannot be read through conventional means (Symbols aren’t fully private) so they remain hidden from the user using your module.

Can serve as a replacement for traditional enum cases where you need to represent concepts.

And really Symbols allow ES6 to provide hooks into objects for your own implementation of say iteration, get/set, or regex solutions and many more.

 Well Known Symbols

You’ve seen the Symbol.iterator override under the iteration protocol blog but Symbols can do so much more. The Symbol.iterator is merely one of many Well Known Symbols.

Here’s an example, lets say you want to make your class respond to instaceof. An ES6 javascript engine would call upon Symbol.hasInstance when it sees instanceof. So for example, a instanceof b would call b[Symbol.hasInstance](a) - or b object’s Symbol.hasInstance method.

class Muggles() {  
    static [Symbol.hasInstance](muggleArray) {
        return Array.isArray(muggleArray);
    }
}
assert([] instanceof Muggles);

This was souced from this terrific blog which has many more examples.

However, Well Known Symbols require a fully functioning ES6 JavaScript engine so libraries such as Babel and core-js does not allow you to use Well Known Symbols or certain cases of using Symbols since they cannot create a new data type.

 
9
Kudos
 
9
Kudos

Now read this

Adapter Pattern in JavaScript

The adapter pattern is a concept where two incompatible interfaces are made to work together using the adapter. The adapter is useful for when changing frameworks in large complex projects. Say you started development using Backbone... Continue →