So far, there seem to be two opposing solutions to immutability in Javascript:
- immutable.js
- seamless-immutable
immutable.js introduces their own (shallowly) immutable objects that are incompatible with the default javascript protocols for objects and arrays.
seamless-immutable uses POJOs that are completely immutable without any magic, but do without structural sharing.
It would be great to combine the best of both worlds. Could immutable prototype chains/trees be a proper solution?
The underlying prototype mechanism gives hope:
var a = [1, 2, 3];
var b = Object.create(a);
b[0]; // 1
b.map(function (x) { return ++x; }); // 2, 3, 4
b.push(4, 5, 6); // initial assignment of b
a; // 1, 2, 3
b; // 1, 2, 3, 4, 5, 6
for (var i = 0; i < b.length; i++) {
console.log(b[i]);
} // 1, 2, 3, 4, 5, 6
a[1] = null; // prototype mutation
a; // 1, null, 3
b; // 1, null, 3, 4, 5, 6
b.unshift(0); // instance mutation
a; // 1, null, 3
b; // 0, 1, null, 3, 4, 5, 6 !!!
Whenever a mutation (unshift) of the current instance (b) makes it impossible for its prototypes to provide their values, the js engine seems to copy these values straight into the instance automatically. I didn't know that, but it makes total sense.
However, working with immutable (keyed/indexed) objects one quickly encounters problems:
var a = [1, 2, 3];
Object.freeze(a);
var b = Object.create(a);
b.push(4, 5, 6); // Error: Cannot assign to read only property "length"
Object.freeze(b);
This one is simple: The length property is inherited from the immutable prototype and hence not mutable. Fixing the problem isn't hard:
var b = Object.create(a, {length: {value: a.length, writable: true}});
But there will probably be other issues, in particular in more complex, real world scenarios.
Maybe someone have already dealt with this idea and can tell me, if it's worth reasoning about it.
Aadit's answer to a related question and Bergi's comment on it touches my question without giving an answer.