Simulating ES6 Symbols In ES5

Symbols, previously known as Names, are a new way to add real private properties to a generic object.

// basic Symbol example
var BehindTheScene = (function(){
var symbol = new Symbol;

function BehindTheScene(){
this[symbol] = {};
}

BehindTheScene.prototype.get = function(k) {
return this[symbol][k];
};

BehindTheScene.prototype.set = function(k, v) {
return this[symbol][k] = v;
};

return BehindTheScene;

}());

var obj = new BehindTheScene;

obj.set('key', 123);

obj.key; // undefined
obj.get('key'); // 123
In few words symbol makes possible to attach properties directly without passing through a WeakMap. A similar behavior could be obtained indeed via WeakMaps:

// similar WeakMap example
var BehindTheScene = (function(){
var wm = new WeakMap;

function BehindTheScene(){
wm.set(this, {});
}

BehindTheScene.prototype.get = function(k) {
return wm.get(this)[k];
};

BehindTheScene.prototype.set = function(k, v) {
return wm.get(this)[k] = v;
};

return BehindTheScene;

}());

var obj = new BehindTheScene;

obj.set('key', 123);

obj.key; // undefined
obj.get('key'); // 123

Why Symbols

To be honest I am not sure but these somehow bring some magic to the object rather than wrapping magic around it, as it is for the WeakMap example, so at least performance should be better ... right? Well, the current shim VS shim says that indexOf() is faster than an implicit toString(): check this test out by yourself ;)
In any case it looks like private symbols will be a better way to go than WeakMap when all we would like to have is a private property. Symbols can be used as Enums too, being unique as any other object is.

Simulating Symbols In Current ES5 JavaScript

As easy as this:

var Symbol;
if (!Symbol) {
Symbol = (function(Object){

// (C) WebReflection Mit Style License

var ObjectPrototype = Object.prototype,
defineProperty = Object.defineProperty,
prefix = '__simbol' + Math.random() + '__',
id = 0;

function get(){/*avoid set w/out get prob*/}

function Symbol() {
var __symbol__ = prefix + id++;
defineProperty(
ObjectPrototype,
this._ = __symbol__,
{
enumerable: false,
configurable: false,
get: get, // undefined
set: function (value) {
defineProperty(this, __symbol__, {
enumerable: false,
configurable: true,
writable: true,
value: value
});
}
}
);
}

defineProperty(Symbol.prototype, 'toString', {
enumerable: false,
configurable: false,
writable: false,
value: function toString() {
return this._;
}
});

return Symbol;

}(Object));
}
A very basic example here:

var sym = new Symbol;
var o = {};
o[sym]; // undefined

o[sym] = 123;
console.log(o[sym]); // 123
for (var k in o) {
console.log(k); // nothing at all
// there is nothing to for/in
}
delete o[sym]; // true
Of course, you can try also the very first example, the one with a shared, private, symbol variable, that will simply work as expected :)
Bear in mind, regardless being a hack, this script does not actually cause any problem to any other script or library you are using today but it needs ES5 compatible browsers such all mobiles plus all desktops and IE9 or greater.

Comments

Popular posts from this blog

8 Things you should not be afraid of as a Developer

News

Why REST is so important