A classic "bad idea" in JS is to alter the prototypes of inbuilt types:
Array.prototype.last = function() { return this[this.length - 1] };
[1,2,3].last() // 3
In ES6 we can extend the inbuilt Array type:
class MyArray extends Array {
last() {
return this[this.length - 1];
}
}
But there's no great way to add these functions without copying:
a = [1, 2, 3]
b = new MyArray(...a);
// [1, 2, 3]
b === a
// False
We can update the object's prototype:
a = [1, 2, 3]
Object.setPrototypeOf(a, MyArray.prototype);
a.last() // 3
Object.setPrototypeOf(a, Array.prototype);
a.last() // TypeError
However, MDN says:
Warning: Changing the
[[Prototype]]of an object is, by the nature of how modern JavaScript engines optimize property accesses, currently a very slow operation in every browser and JavaScript engine.
Helper functions or container classes can help, but their syntax is unwieldy:
ArrayHelper.last(a); // 3
MyArrayWrapper(a).last(); // 3
MyArrayWrapper.get(0); // Ugh, we lose []-based indexing.
The ideal solution would be something like:
a = [1, 2, 3];
b = asMyArray(a);
b.last(); // 3
a.last(); // TypeError
// But avoid doing a copy, and have both objects reference the same memory:
b[0] = 10;
a[0] == 10; // true
or, if it's easier
a = [1, 2, 3];
applyMyArrayPrototype(a);
a.last(); // 3
a.dropMyArrayPrototype();
a.last(); // TypeError
Is there a way to achieve this in JS?