Monday, September 21, 2015

Symbols - New in Node 4

In continuing my discussions of new ES6 language features now available in Node 4, today I'm turning my attention to Symbols.

I'm not as sold on Symbols as I am on some of the other new features. What is a Symbol? A technical explanation is that Symbols are unique and immutable data types. Their purpose is to provide another way of making private properties on objects.

Ecmascript 6: The Future is Now!

Making Symbols is easy.

var sym1 = Symbol();
var sym2 = Symbol("whatnot");
var sym3 = Symbol("whatnot");

console.log(sym2 == sym3);  // false
console.log(sym2 === sym3); // false

The string parameter passed to Symbol() is optional and simply serves as a label. It doesn't mean anything to the Symbol itself. Making another Symbol with the same label doesn't mean the two Symbols are equal. Each Symbol created is unique.

So what does one do with these Symbols? I said that they're used for making private properties on objects, but how is that accomplished?

Let's start by defining the problem. When you have an object, JavaScript provides no protection of its properties. They can be redefined, or even removed! Consider this example.

var Frog = (function() {

    function Frog(type) {
        this.type = type;
    }

    Frog.prototype.getType = function() {
        return this.type;
    };

    return Frog;

}());

var f = new Frog("Science");
console.log(f.getType()); // prints Science

f.type = 27;
console.log(f.getType()); // prints 27

delete f.type;
console.log(f.getType()); // prints undefined

How can the frog type be made immutable outside of its own functions? Symbols are one possibility. Look at this code, slightly modified to use Symbols.

var Frog = (function() {

    var typeSymbol = Symbol("type");

    function Frog(type) {
        this[typeSymbol] = type;
    }

    Frog.prototype.getType = function() {
        return this[typeSymbol];
    };

    return Frog;

}());

var f = new Frog("CEO");
console.log(f.getType()); // prints CEO

console.log(f.type); // prints undefined

console.log(f["type"]); // prints undefined

var s = Symbol("type");
console.log(f[s]); // prints undefined

delete f.type;
console.log(f.getType()); // prints CEO

Instead of setting and accessing the frog type property internally using the dot notation (this.type), this code uses the bracket notation (this["type"]). BUT it uses the Symbol instead of the string "type" to make it inaccessible from outside. All attempts to read or delete the private type property will be unsuccessful. Even trying to do it with another Symbol fails, because Symbols made with the same label are not equivalent.

So that's Symbols. There are of course other ways to make fields private in JavaScript, such as using more closures or with Object.defineProperty. I haven't experienced any scenario where Symbols are really that much better than the previously available alternatives, but it's always nice to have more options.

I can't think of any way to tie this to the Amphibian.com comic for today, so here's the link to it without further comment.

Amphibian.com comic for 21 September 2015