Nazanin De's Blog

Projects, Ideas and thoughts

Reflection in ES6 with Symbol, Proxy and Reflect - Part 1

Really Reflection in ES6? YES! ES6 has three awesome language feature which you can leverage to apply reflection and some cool meta programming. How?

  • Symbols are all about Reflection within implementation - you sprinkle them on your existing classes and objects to change the behavior.

  • Reflect is all about Reflection through introspection - used to discover very low level information about your code.

  • Proxy is all about Reflection through intercession - wrapping objects and intercepting their behaviors through traps.

So what all these good for? In this post I am gonna cover usages of Symbols.

All programming languages have their built in data structures and often they are very different from each other. Since Javascript is loosely-typed and dynamic language there is no need to declare the type of the variable ahead of time. The type of variables will get configured automatically on processing time hence we can use same variable name for multiple types.

In ES5 we had six dataTypes as following:
Primitives:

  • String
  • Null
  • Undefined
  • Number
  • Boolean

and Non-primitives:

  • Object

In ES6 we have one more primitive type added to language primitive and that is Symbol. A Symbol is a unique and immutable primitive and can be set as object property.
In other languages you can find Symbols too. In C++ win32 library ATOM is a 16-bit Windows handle-like primitive exists in an atom table. An atom table is a system-defined table that stores strings and corresponding identifiers. An application places a string in an atom table and receives a 16-bit integer, called an atom, that can be used to access the string. A string that has been placed in an atom table is called an atom name. Atom can also be found in Prolog programming language too. In C symbols gets the shape of enumeration(enum).

How to use symbols?

Symbols are values Javascript program can create and use as object property keys without encountering name collisions. You can define a symbol in the following way:

 var sym = Symbol(); 

Calling Symbol() creates a new symbol, a value that’s not equal to any other value.

Just like a string or number, you can use a symbol as a property key. Because it’s not equal to any string, this symbol-keyed property is guaranteed not to collide with any other property.

Symbols cannot get initialized with new keyword and if they do an TypeError will be thrown.

var sym = new Symbol() //logs TypeError  
var myObj = {};  
myObj[Symbol('foo')] = 'foo';  
console.log(myObj);  //logs: Object {Symbol(foo): "foo"}  

Because symbol keys were designed to avoid collisions, JavaScript’s most common object-inspection features simply ignore symbol keys. A for-in loop, for instance, only loops over an object’s string keys. Symbol keys are skipped. Object.keys(obj) and Object.getOwnPropertyNames(obj) do the same. But symbols are not exactly private: it is possible to use the new API Object.getOwnPropertySymbols(obj) to list the symbol keys of an object. Another new API, Reflect.ownKeys(obj), returns both string and symbol keys.

myObj.d = 'd';

for(var i in myObj) {  
   console.log(i); //logs "d" only
}

It is important to know that symbols cannot cast to Sting automatically so if you do:

var sym = Symbol(':-o');  
console.log(sym + 'Hi there!');  
// logs TypeError: Cannot convert a Symbol value to a string

If you would like to convert a symbol to String you can use String(sym) or sym.toString().

Where to use symbols?
  • As object properties to avoid collision and putting metadata
  • As a unique value ( enums )
  • As a way for developers to overwrite APIs with Inspect Symbol

Symbols are implemented in Firefox 36 and Chrome 38. You can play with symbols and their awesome functionalities easily in chrome developer tools console.