Subclassing Arrays in ES2015

Thursday,
September
21st,
2017

Prior to ES2015 (ES6), you couldn’t really subclass an array in JavaScript without a few caveats, which kangax outlines in a fantastic post called How ECMAScript 5 still does not allow to subclass array. Now in ES2015, you can. This can be useful for defining custom collection classes that leverage all of the array methods and properties while also automatically implementing the iterable and iterator protocols, which I wrote about recently. In short, objects that implement these protocols can be looped through with the for...of loop or can be used with the spread operator.

Subclassing An Array With ES2015 Classes

Let’s say you want to define a collection class with an average method. You can do that using a class:

Can You Subclass An Array Without A Class?

I then wondered if it was possible to subclass an array without a class. It turns out you can’t, but you can read about several different approaches in How ECMAScript 5 still does not allow to subclass array. However, in that post kangax goes over an approach that does work, which uses something that is now standardized in ES2015, and that is __proto__. Basically this approach takes an array and changes its prototype to another object that inherits from Array.prototype. Here is a slightly modified version of that approach:

Here, the Collection constructor function returns an array instead of the object being constructed, and this array has its prototype changed to another object that inherits from Array.prototype.

This approach leverages Object.setPrototypeOf which was introduced in ES2015 as a way to set the prototype of an object to another object. Prior to this being introduced, the only way to change the prototype of an object was to use the non-standard __proto__ property, so Collection would look like this instead:

Performance Comparison

If you checked out the documentation for Object.setPrototypeOf, you may have noticed the big red warning stating that changing the prototype of an object is a slow operation.

I ran a JSPerf test comparing these two approaches to subclassing an array, and results varied across browsers.

Support

In terms of support, subclassing an array with a class isn’t something that Babel can polyfill without a few caveats, since __proto__ wasn’t standardized until ES2015, and Object.setPrototypeOf wasn’t added until ES2015. However, browser and Node support is pretty good, which you can see here.

Conclusion

To summarize, you can subclass an array using a class. Without a class, you can subclass an array by creating an array using the Array constructor or literal notation ([]) and changing its prototype to another object that inherits from Array.prototype. Although this approach is faster, I would still recommend using a class for better readability until performance becomes a problem.