Peculiarities of EcmaScript 6 Symbol type…
Something awesome, something new...
EcmaScript, the de facto client-side scripting language most commonly implemented by the name JavaScript has had the official specifications of its 6th edition out in June this year. Web app development would be taken to a whole new level as browser vendors implement this new spec. One of the things I’m most interested in at the moment is the Symbol type.
Note: Symbols are a recent development and are only usable in current browsers. Edge and Firefox fully implement it while Chrome has most of Symbol’s features. Safari has not yet implemented symbols so do not use it in your production code just yet.
What is it?
EcmaScript 6 spec defines the Symbol type as the set of all the non-string values that may be used as the key of an Object property. What does that mean? Let’s say you’ve created an object like the following.
var obj = { a: 'Hello', b: 'World' }
Here obj.a
would get you the string “Hello” and obj.b
would “World”. In this, a
and b
are keys of the object obj
– string keys. Since objects also act as associative arrays the same properties can be accessed using obj['a']
and obj['b']
.
Instead of having those as keys, you can, in EcmaScript 6, use symbols as keys.
How’s that done?
A symbol can be created using the Symbol function.
var sym = Symbol()
With that in place you can now add a property to the object with that symbol as the key.
obj[sym] = 'Universe'
Sure, but how is that any different from string keys?
Well, properties with string keys can be accessed using the string literal. There is no literal syntax for symbols. This means the only way for me to access the string “Universe” trapped within the object obj
is to use the variable sym
that references the symbol.
Where is this useful?
Until ES6, the concept of private variables in a class didn’t exist. One could use variables declared with the var keyword and made use of it using what are called privileged methods. But that variable would not be accessible to public methods – those that are property of the class’ prototype.
var SomeClass = (function () { function SomeClass () { var privateVariable = 'Hello' this.privilegedMethod = function () { return privateVariable } } SomeClass.prototype.publicMethod = function () { return privateVariable } return SomeClass })() var abc = new SomeClass() console.log( abc.privilegedMethod() ) // logs 'Hello' console.log( abc.publicMethod() ) // throws an error
The publicMethod cannot access the variable declared in SomeClass
’s constructor. This can be done but the privileged method is created one per instance of the SomeClass
function. There are workarounds to this, but all involve creating a second object that holds a reference to instances of the class, thus making it impossible for JavaScript’s garbage collector to clean up.
Symbols solve that issue while adding the ability for classes to hold a quasi-private variable. Let’s rewrite that class and its methods.
var SomeClass = (function () { var privateVariable = Symbol() function SomeClass () { this[privateVariable] = 'Hello' this.privilegedMethod = function () { return this[privateVariable] } } SomeClass.prototype.publicMethod = function () { return this[privateVariable] } return SomeClass })() var abc = new SomeClass() console.log( abc.privilegedMethod() ) // logs 'Hello' console.log( abc.publicMethod() ) // logs 'Hello'
Now, I said quasi-private because using symbols as keys just prevents access to or rather obscures those properties. There is no straightforward way to do it. I can still access them using the Object.getOwnPropertySymbols
function.
var syms = Object.getOwnPropertySymbols( abc ) console.log( abc[ syms[0] ] ) // logs 'Hello'
Peculiarities
The Symbol type is very different from other types. Here’s how.
Symbols are created without the ‘new’ keyword
The
Symbol
function directly returns an instance of it without the ‘new’ keyword. In fact, using the ‘new’ keyword will throw.var sym = Symbol() // this is fine var bol = new Symbol() // this will throw
No two symbols are the same
Every function call made to
Symbol
will return a different symbol.Symbol() === Symbol() // returns false
Symbols’ typeof can be easily checked
Running the typeof of a symbol returns the string “symbol”
typeof sym // returns "symbol"
That seems like an expected outcome doesn’t it. Wait till you see what happens next.
A symbol is not an instance of
Symbol
apparentlyRunning an instanceof statement with the Symbol and its instance.
sym instanceof Symbol // returns false
A symbol’s constructor is Symbol
Checking the
constructor
property of symbol will return the functionSymbol
even though it does not identify as an instance of Symbol.console.log( sym.constructor ) // logs Symbol() sym.constructor === Symbol // returns true sym instanceof sym.constructor // returns false
In fact, symbols are the only things that do this. Every other object and every literal will return true if their
instanceof
is checked with the constructor of their type.Symbols can be cast into an object
By passing a symbol as a parameter to Object, we get the Symbol object that will return true on instanceof Symbol.
var symObj = Object(sym) symObj.constructor === Symbol // returns true symObj instanceof Symbol // returns true
This is very different from other types as event the literals will be coerced to objects when they’re instanceof is checked. That doesn’t happen with Symbols without some extra work.
Symbols can’t be coerced easily
Running any literal or object through the Object function that to itself will return true.
Object(m) == m
The above statement will return true for literally every value of
m
except for undefined, null and now all symbol instances.
I don’t see these quirks as problematic. To me, it’s kind of nice not to have a completely sensible method to access this type. Symbols are quite worthless as a type save for their ability to act as keys for object properties. It’s a simple solution to a lot of problems with object oriented programming in JavaScript. Whether or not they identify as being instance of Symbol is not something I foresee us caring about.
That’s it!
That was all I had about the peculiarities of symbols. I’d go so far as to say symbols are one of the best additions to EcmaScript and we’re about to use it a lot.
So, let me know what you think of this. Are there other ways symbols act funny that I haven’t mentioned? Are there any factual errors in this article? Do you want me to write about something? Let me know in the comments.
Until the next time…