ECMAScript | Экзотические объекты Массивов

ECMAScript | Экзотические объекты Массивов

 

Объект Array — это экзотический объект, который обеспечивает особую обработку ключей свойств индекса массива (смотри раздел 6.1.7). Свойство, чьё имя свойства является индексом массива, также называется «элементом» (element). Каждый объект Array имеет ненастраиваемое свойство длины «length«, значение которого всегда является неотрицательным целым числом, математическое значение которого меньше 232. Значение свойства «length» численно больше, чем имя каждого собственного свойства, имя которого — индекс массива; всякий раз, когда создается или изменяется собственное свойство объекта Array, другие свойства корректируются по мере необходимости, чтобы поддерживать этот инвариант.

В частности, всякий раз, когда добавляется собственное свойство, имя которого является индексом массива, значение свойства длины «length» изменяется, если необходимо, на единицу больше, чем числовое значение этого индекса массива; и всякий раз, когда значение свойства «length» изменяется, каждое собственное свойство, имя которого является индексом массива, значение которого не меньше новой длины, удаляется. Это ограничение применяется только к собственным свойствам объекта Array и не зависит от длины «length» или свойств индекса массива, которые могут быть унаследованы от его прототипов.

Примечание

Строковое имя свойства P является индексом массива тогда и только тогда, когда ToString(ToUint32(P)) равно P, а ToUint32(P) не совпадает со значением 𝔽(232-1).

Объект является «экзотическим объектом Array» (Array exotic object) (или просто объектом Array), если его внутренний метод [[DefineOwnProperty]] использует следующую реализацию, а его другие важные внутренние методы используют определения, найденные в разделе 10.1. Эти методы установлены в ArrayCreate.

 

 

[[DefineOwnProperty]] ( P, Desc )

Внутренний метод [[DefineOwnProperty]] экзотического объекта ArrayA принимает аргументы P (ключ свойства) и Desc (дескриптор свойства). При вызове он выполняет следующие шаги:

1. Утверждено: IsPropertyKey(P) является true (истинно).
2. Если P является длиной "length", то
   a. Вернуть ? ArraySetLength(A, Desc).
3. Иначе, если P является индексом массива, тогда
   a. Пусть oldLenDesc будет OrdinaryGetOwnProperty(A, "length").
   b. Утверждено: ! IsDataDescriptor(oldLenDesc) является true (истинно).
   c. Утверждено: oldLenDesc.[[Configurable]] является false (ложным).
   d. Пусть oldLen будет oldLenDesc.[[Value]].
   е. Утверждено: oldLen - это неотрицательное целое число.
   f. Пусть index будет! ToUint32(P).
   g. Если indexoldLen и oldLenDesc.[[Writable]] имеет значение false, вернуть false.
   h. Пусть succeeded будет ! OrdinaryDefineOwnProperty(A, P, Desc).
   i. Если succeeded является false, вернуть false.
   j. Если indexoldLen, тогда
      i. Установить oldLenDesc.[[Value]] на index + 1𝔽.
      ii. Установить значение OrdinaryDefineOwnProperty(A, "length", oldLenDesc).
      iii. Утверждено: succeeded является true (истинно).
   k. Вернуть true.
4. Вернуть OrdinaryDefineOwnProperty(A, P, Desc).

 

ArrayCreate ( length [ , proto ] )

Абстрактная операция ArrayCreate (Создать массив) принимает аргументы длины length (неотрицательное целое число) и необязательный аргумент proto. Он используется для указания создания новых экзотических объектов Array. При вызове она выполняет следующие шаги:

1. Если длина length > 232 - 1, выбросить исключение RangeError.
2. Если proto отсутствует, установите proto в %Array.prototype%.
3. Пусть А будет ! MakeBasicObject(«[[Prototype]], [[Extensible]]»).
4. Установите A.[[Prototype]] на proto.
5. Установите A.[[DefineOwnProperty]], как указано в 10.4.2.1.
6. Выполнить ! OrdinaryDefineOwnProperty(A, "length", PropertyDescriptor { [[Value]]: 𝔽(length), [[Writable]]: true, [[Enumerable]]: false, [[Configurable]]: false }).
7. Вернуть A.

 

ArraySpeciesCreate ( originalArray, length )

Абстрактная операция ArraySpeciesCreate (Создание массива видов) принимает аргументы originalArray и length (неотрицательное целое число). Он используется для указания создания нового объекта Array с помощью функции-конструктора, производной от originalArray. При вызове она выполняет следующие шаги:

1. Пусть isArray будет ? IsArray(originalArray).
2. Если isArray является false (ложно), вернуть ? ArrayCreate(length).
3. Пусть C будет? Получить(originalArray, "constructor").
4. Если IsConstructor(C) является true (истинно), то
   а. Пусть thisRealm будет текущей записью Realm.
   b. Пусть realmC будет ? GetFunctionRealm(С).
   c. Если thisRealm и realmC не являются одной и той же записью Realm, тогда
      i. Если SameValue(C, realmC.[[Intrinsics]].[[%Array%]]) является true (истинно), установите для C значение undefined.
5. Если Тип(C) - это Объект, то
   а. Установите C на ? Получить(C, @@species).
   b. Если C имеет значение null, установите C в значение undefined.
6. Если C является undefined(не определено), вернуть ? ArrayCreate(length).
7. Если IsConstructor(C) имеет значение false, выбросить исключение TypeError.
8. Вернуть ? Построить(C, «𝔽(length)»).
Примечание

Если originalArray был создан с использованием стандартного встроенного конструктора Array для области, которая не является областью текущего контекста выполнения, то новый массив создается с использованием области текущего контекста выполнения. Это обеспечивает совместимость с веб-браузерами, которые исторически имели такое поведение для методов Array.prototype, которые теперь определены с помощью ArraySpeciesCreate.

 

ArraySetLength ( A, Desc )

Абстрактная операция ArraySetLength (Установка длины массива) принимает аргументы A (объект Array) и Desc (дескриптор свойства). При вызове она выполняет следующие шаги:

1. Если Desc.[[Value]] отсутствует, тогда
   а. Вернуть OrdinaryDefineOwnProperty(A, "length", Desc).
2. Пусть newLenDesc будет копией Desc.
3. Пусть newLen будет ? ToUint32(Desc.[[Value]]).
4. Пусть numberLen будет ? ToNumber(Desc.[[Value]]).
5. Если newLen не совпадает со значением numberLen, вызовите исключение RangeError.
6. Установите для newLenDesc.[[Value]] значение newLen.
7. Пусть oldLenDesc будет OrdinaryGetOwnProperty(A, "length").
8. Утверждено: ! IsDataDescriptor(oldLenDesc) является true (истинно).
9. Утверждено: oldLenDesc.[[Configurable]] является false (ложно).
10. Пусть oldLen будет oldLenDesc.[[Value]].
11. Если newLenoldLen, то
   а. Вернуть OrdinaryDefineOwnProperty(A, "length", newLenDesc).
12. Если oldLenDesc.[[Writable]] имеет значение false, вернуть false.
13. Если newLenDesc.[[Writable]] отсутствует или имеет значение true, пусть newWritable будет true.
14. Иначе,
   а. ПРИМЕЧАНИЕ. Установка для атрибута [[Writable]] значения false откладывается на случай, если какие-либо элементы не могут быть удалены.
   b. Пусть newWritable будет false.
   c. Установите для newLenDesc.[[Writable]] значение true.
15. Пусть succeeded будет ! OrdinaryDefineOwnProperty(A, "length", newLenDesc).
16. Если succeeded имеет значение false, вернуть false.
17. Для каждого собственного ключа свойства P элемента A, который является индексом массива, числовое значение которого больше или равно newLen, в порядке убывания числового индекса, выполните
   а. Пусть deleteSucceeded будет ! A.[[Delete]](P).
   b. Если deleteSucceeded имеет значение false, то
      i. Установите для newLenDesc.[[Value]] значение ! ToUint32(P) + 1𝔽.
      ii. Если newWritable имеет значение false, установите для newLenDesc.[[Writable]] значение false.
      iii. Выполнить ! OrdinaryDefineOwnProperty(A, "length", newLenDesc).
      iv. Вернуть false.
18. Если newWritable является false (ложно), тогда
   а. Установить succeeded на ! OrdinaryDefineOwnProperty(A, "length", PropertyDescriptor {[[Writable]]: false}).
   b. Утверждено: succeeded является true (истинно).
19. Вернуть true.
Примечание

На шагах 3 и 4, если Desc.[[Value]] является объектом, его метод valueOf вызывается дважды. Это устаревшее поведение, которое было указано с этим эффектом, начиная со 2-го издания данной спецификации.

 

Информационные ссылки

Предыдущий раздел — Экзотические объекты Связанных Функций

Стандарт ECMAScript — Раздел «Array Exotic Objects» — https://tc39.es/ecma262/#sec-array-exotic-objects