The article discusses how to create an array "subclass". That is, we want to create an object that has Array.prototype
in its prototype chain, but with an immediate prototype parent that is not Array.prototype
(i.e., so that the prototype parent can provide additional methods beyond the array prototype).
That article says that a fundamental difficulty in creating an array "subclass" is that arrays get their behavior from both
- their prototype, and
- simply being array instances.
If arrays inherited all their behavior from Array.prototype
, our work would be very quick. We would simply create an object whose prototype chain includes Array.prototype
. That object would make an ideal prototype for our array-subclass instances.
However, arrays have special automatic behaviors that are unique to array instances, and are not inherited from the prototype. (In particular, I mean the behaviors around the length
property automatically changing when the array changes, and vice versa.) These are behaviors supplied to each array instance when it is created by the Array
constructor, and there is no way to mimic them faithfully in ECMAScript 5. Therefore, the instance of your array subclass must be originally created by the Array
constructor. This is non-negotiable, if we want the appropriate length
behaviors.
This requirement conflicts with our other requirement that the instance must have a prototype that is not Array.prototype
. (We don't want to add methods to Array.prototype
; we want to add methods to an object that uses Array.prototype
as its own prototype .) In ECMAScript 5, any object created using the Array
constructor must have the prototype parent of Array.prototype
. The ECMAScript 5 spec provides no mechanism to change an object's prototype after it is created.
By contrast, ECMAScript 6 does provide such a mechanism. Your approach is quite similar to the __proto__
-based approach described in the article, under the section "Wrappers. Prototype chain injection.," except you use ECMAScript 6's Object.setPrototypeOf
instead of __proto__
.
Your solution correctly satisfies all of the following requirements:
- Each instance actually is an array (i.e., has been constructed by the
Array
constructor). This ensures that the [[Class]]
internal property is correct, and length
behaves correctly.
- Each instance has an immediate prototype that is not
Array.prototype
, but still includes Array.prototype
in its prototype chain.
These requirements were previously impossible to satisfy in ES5, but ES6 makes it fairly easy. In ES5, you could have an array instance that fails to satisfy requirement #2, or a plain object that fails to satisfy requirement #1.
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…