I have heard that ES6 now finally permits subclassing Array. Here's an example given by
class Stack extends Array {
constructor() { super() }
top() { return this[this.length - 1]; }
}
var s = new Stack();
s.push("world");
s.push("hello");
console.log(s.top()); // "hello"
console.log(s.length); // 2
Sure, that works. But in Traceur at least, setting the length explicitly does not truncate the array. And when printing via console.log, the output is in object form rather than array form, suggesting that somebody is not looking at it as a "real" array.
Is this a problem with how Traceur implements subclassing built-in objects, or a limitation of ES6?
In the normal case, the subclassing in Ecmascript 6 is just syntactic sugaring, so it still does the prototypical chaining that Ecmascript 5 does. This means that extending types in Traceur is in most cases exactly the same as extending in "real" ecmascript 6.
Array instances are special – the ECMAScript 6 specification calls them exotic. Their handling of the property length can’t be replicated via normal JavaScript. If you invoke your constructor then an instance of Stack is created, not an exotic object (exotic is actually the official name in the ES6 spec).
But do not despair, the solution is not provided by the class extends
sugaring itself, but by the (re)introduction of the __proto__
property.
Ecmascript 6 reintroduces the writable __proto__
property. It was once only available on Firefox and was deprecated, but is now back in full force in ES6. This means that you can create a real array and then "upgrade" it to your custom class.
So now you can do the following:
function Stack(len) {
var inst = new Array(len);
inst.__proto__ = Stack.prototype;
return inst;
}
Stack.prototype = Object.create(Array.prototype);
So subclassing should work in ES6. You might have to use the __proto__
trick manually if they have not manage to sugar the process using the new class extends
syntax with some yet undisclosed trickery. You will not be able to use the transpilers such as Traceur and Typescript to accomplish this in ES5, but you might be able to use the code above in ES5 using Firefox that (as far as I remember) have supported __proto__
for quite some time.