Ответ 1
В статье обсуждается, как создать массив "подкласс". То есть мы хотим создать объект с Array.prototype
в цепочке прототипов, но с непосредственным родителем-прототипом, который не является Array.prototype
(т.е. Родитель-прототип может предоставить дополнительные методы за пределами прототипа массива).
В этой статье говорится, что фундаментальная трудность создания массива "подкласс" заключается в том, что массивы получают свое поведение от обоих
- их прототип, и
- просто являются экземплярами массива.
Если массивы унаследовали все их поведение от Array.prototype
, наша работа была бы очень быстрой. Мы просто создали бы объект, чья цепочка прототипов включает Array.prototype
. Этот объект станет идеальным прототипом для наших экземпляров массива-подкласса.
Однако массивы имеют специальное автоматическое поведение, уникальное для экземпляров массива и не унаследованное от прототипа. (В частности, я имею в виду поведение вокруг свойства length
, которое автоматически изменяется при изменении массива и наоборот). Это поведение, предоставляемое каждому экземпляру массива, когда оно создается конструктором Array
, и нет способа чтобы точно имитировать их в ECMAScript 5. Поэтому экземпляр вашего подкласса массива должен быть первоначально создан конструктором Array
. Это не подлежит обсуждению, если мы хотим, чтобы соответствующие поведения length
.
Это требование противоречит нашему другому требованию о том, что экземпляр должен иметь прототип, который не является Array.prototype
. (Мы не хотим добавлять методы к Array.prototype
, мы хотим добавить методы к объекту, который использует Array.prototype
в качестве своего собственного прототипа.) В ECMAScript 5 любой объект, созданный с использованием конструктора Array
, должен иметь прототип родительский элемент Array.prototype
. Спецификация ECMAScript 5 не предоставляет механизма для изменения прототипа объекта после его создания.
В отличие от этого ECMAScript 6 предоставляет такой механизм. Ваш подход очень похож на подход, основанный на __proto__
, описанный в статье, в разделе " Wrappers. Вставка цепи прототипа.," except вы используете ECMAScript 6 Object.setPrototypeOf
вместо __proto__
.
Ваше решение правильно удовлетворяет всем следующим требованиям:
- Каждый экземпляр фактически представляет собой массив (т.е. был сконструирован конструктором
Array
). Это гарантирует правильность внутреннего свойства[[Class]]
, аlength
ведет себя правильно. - Каждый экземпляр имеет непосредственный прототип, который не является
Array.prototype
, но все еще содержитArray.prototype
в цепочке прототипов.
Эти требования ранее не были удовлетворены в ES5, но ES6 делает его довольно простым. В ES5 у вас может быть экземпляр массива, который не удовлетворяет требованию №2 или простому объекту, который не удовлетворяет требованию № 1.