ECMAScript | Экзотические объекты Аргументов

ECMAScript | Экзотические объекты Аргументов

 

Большинство функций ECMAScript делают «объект аргументов» (arguments object) доступным для своего кода. В зависимости от характеристик определения функции ее объект аргументов является либо «обычным объектом» (ordinary object), либо «экзотическим объектом аргументов» (arguments exotic object). Экзотический объект аргументов — это экзотический объект, свойства индекса массива которого сопоставляются с привязками формальных параметров при вызове связанной с ним функции ECMAScript.

Объект является экзотическим объектом аргументов (arguments exotic object), если его внутренние методы используют следующие реализации, а те, которые здесь не указаны, используют те, что были в разделе 10.1. Эти методы устанавливаются в CreateMappedArgumentsObject.

Примечание 1

Хотя CreateUnmappedArgumentsObject сгруппирован в это предложение, он создает обычный объект, а не экзотический объект с аргументами.

Экзотические объекты аргументов имеют те же внутренние слоты, что и обычные объекты. У них также есть внутренний слот [[ParameterMap]]. Объекты обычных аргументов также имеют внутренний слот [[ParameterMap]], значение которого всегда не определено. Для обычных объектов аргументов внутренний слот [[ParameterMap]] используется Object.prototype.toString (20.1.3.6) только для их идентификации.

 

Примечание 2

Свойства данных с целочисленным индексом экзотического объекта аргументов, значения числового имени которого меньше, чем количество формальных параметров соответствующего объекта функции, изначально совместно используют свои значения с соответствующими привязками аргументов в контексте выполнения функции. Это означает, что изменение свойства изменяет соответствующее значение привязки аргумента и наоборот. Это соответствие нарушается, если такое свойство удаляется и затем переопределяется, или если свойство изменяется на свойство доступа. Если объект аргументов является обычным объектом, значения его свойств являются просто копией аргументов, переданных функции, и нет никакой динамической связи между значениями свойств и значениями формальных параметров.

Примечание 3

Объект ParameterMap и значения его свойств используются в качестве устройства для определения соответствия объекта аргументов привязкам аргументов. Объект ParameterMap и объекты, являющиеся значениями его свойств, не наблюдаются напрямую из кода ECMAScript. Реализации ECMAScript не нужно фактически создавать или использовать такие объекты для реализации указанной семантики.

Примечание 4

Объекты с обычными аргументами определяют неконфигурируемое свойство доступа с именем «callee» (вызываемый), которое вызывает исключение TypeError при доступе. Свойство «callee» имеет более конкретное значение для экзотических объектов аргументов, которые создаются только для некоторого класса нестрогих функций. Определение этого свойства в обычном варианте существует для того, чтобы гарантировать, что оно не будет определено каким-либо другим образом в соответствии с реализациями ECMAScript.

Примечание 5

Реализации экзотических объектов аргументов в ECMAScript исторически содержали свойство доступа с именем «caller» (вызыватель). До ECMAScript 2017 эта спецификация включала определение бросающего свойства «caller» для обычных объектов аргументов. Поскольку реализации больше не содержат это расширение, ECMAScript 2017 отказался от требования к методу доступа «caller«.

 

 

[[GetOwnProperty]] ( P )

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

1. Пусть desc будет OrdinaryGetOwnProperty(args, P).
2. Если desc является undefined, верните desc.
3. Пусть map будет args.[[ParameterMap]].
4. Пусть isMapped будет ! HasOwnProperty(map, P).
5. Если isMapped является true (истинно), тогда
   а. Установите для desc.[[Value]] значение Get(map, P).
6. Вернуть desc.

 

[[DefineOwnProperty]] ( PDesc )

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

1. Пусть map будет args.[[ParameterMap]].
2. Пусть isMapped будет HasOwnProperty(map, P).
3. Пусть newArgDesc будет Desc.
4. Если isMapped является true (истинно) и IsDataDescriptor(Desc) является true (истинно), тогда
   а. Если Desc.[[Value]] отсутствует, а Desc.[[Writable]] присутствует и его значение false, то
      i. Установите newArgDesc на копию Desc.
      ii. Установите для newArgDesc.[[Value]] значение Get(map, P).
5. Пусть allowed будет ? OrdinaryDefineOwnProperty(args, P, newArgDesc).
6. Если allowed является false, вернуть false.
7. Если isMapped является true (истинно), тогда
   а. Если IsAccessorDescriptor(Desc) является true (истинно), тогда
      i. Вызвать map.[[Delete]](P).
   b. Еще,
      i. Если присутствует Desc.[[Value]], тогда
         1. Пусть setStatus будет Set(map, P, Desc.[[Value]], false).
         2. Утверждено: setStatus является true (истинно), потому что формальные параметры, отображаемые объектами аргументов, всегда доступны для записи.
      ii. Если Desc.[[Writable]] присутствует и его значение false, то
         1. Вызвать map.[[Delete]](P).
8. Верните истину true.

 

[[Get]] ( PReceiver )

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

1. Пусть map будет args.[[ParameterMap]].
2. Пусть isMapped будет ! HasOwnProperty(map, P).
3. Если isMapped имеет значение false, тогда
   а. Вернуть ? OrdinaryGet(args, P, Receiver).
4. Иначе,
   а. Утверждено: map содержит отображение формальных параметров для P.
   b. Вернуть Get(map, P).

 

[[Set]] ( PVReceiver )

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

1. Если SameValue(args, Receiver) является false (ложно), тогда
   а. Пусть isMapped будет false ложным.
2. Иначе,
   а. Пусть map будет args.[[ParameterMap]].
   b. Пусть isMapped будет ! HasOwnProperty(map, P).
3. Если isMapped является true (истинно), то
   а. Пусть setStatus будет установить Set(map, P, V, false).
   b. Утверждено: setStatus является true (истинно), потому что формальные параметры, отображаемые объектами аргументов, всегда доступны для записи.
4. Вернуть ? OrdinarySet(args, P, V, Receiver).

 

[[Delete]] ( P )

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

1. Пусть map будет args.[[ParameterMap]].
2. Пусть isMapped будет ! HasOwnProperty(map, P).
3. Пусть result будет ? Обычное удаление(args, P).
4. Если результат result - истина true, а isMapped - истина true, тогда
   а. Вызвать map.[[Delete]](P).
5. Вернуть результат result.

 

CreateUnmappedArgumentsObject ( argumentsList )

Абстрактная операция CreateUnmappedArgumentsObject (Создать объект несопоставленных аргументов) принимает аргументы argumentsList. При вызове он выполняет следующие шаги:

1. Пусть len будет количеством элементов в argumentsList.
2. Пусть obj будет ! OrdinaryObjectCreate(%Object.prototype%, «[[ParameterMap]]»).
3. Установите для obj.[[ParameterMap]] значение undefined.
4. Выполните DefinePropertyOrThrow(obj, "length", PropertyDescriptor {[[Value]]: 𝔽(len), [[Writable]]: true, [[Enumerable]]: false, [[Configurable]]: true}).
5. Пусть index равен 0.
6. Повторите, пока index < len,
   а. Пусть val будет argumentsList[index].
   b. Выполнить ! CreateDataPropertyOrThrow(obj, ! ToString(𝔽(index)), val).
   c. Установите index на index + 1.
7. Выполнить ! DefinePropertyOrThrow(obj, @@iterator, PropertyDescriptor {[[Value]]: %Array.prototype.values%, [[Writable]]: true, [[Enumerable]]: false, [[Configurable]]: true}).
8. Выполнить ! DefinePropertyOrThrow(obj, "callee", PropertyDescriptor {[[Get]]: %ThrowTypeError%, [[Set]]: %ThrowTypeError%, [[Enumerable]]: false, [[Configurable]]: false} ").
9. Вернуть obj.

 

CreateMappedArgumentsObject ( func, formals, argumentsList, env )

Абстрактная операция CreateMappedArgumentsObject (Создать объект сопоставленных аргументов) принимает аргументы func (объект), формальные выражения formals (узел синтаксического анализа), argumentsList (Список) и env (запись среды). При вызове она выполняет следующие шаги:

1. Утверждено: formals не содержит параметра rest, каких-либо шаблонов привязки или каких-либо инициализаторов. Он может содержать повторяющиеся идентификаторы.
2. Пусть len будет количеством элементов в argumentsList.
3. Пусть obj будет ! MakeBasicObject(« [[Prototype]], [[Extensible]], [[ParameterMap]] »).
4. Установить для obj.[[GetOwnProperty]], как указано в 10.4.4.1.
5. Установить для obj.[[DefineOwnProperty]], как указано в 10.4.4.2.
6. Установить для obj.[[Get]], как указано в 10.4.4.3.
7. Установить для obj.[[Set]], как указано в 10.4.4.4.
8. Установить для obj.[[Delete]], как указано в 10.4.4.5.
9. Установить для obj.[[Prototype]] значение %Object.prototype%.
10. Пусть map будет ! OrdinaryObjectCreate(null).
11. Установить для obj.[[ParameterMap]] на map.
12. Пусть parameterNames будет BoundNames из formals.
13. Пусть numberOfParameters будет количеством элементов в parameterNames.
14. Пусть index равен 0.
15. Повторить, пока index < len,
   а. Пусть val будет argumentsList[index].
   b. Выполнить ! CreateDataPropertyOrThrow(obj, ! ToString(𝔽(index)), val).
   c. Установите index на index + 1.
16. Выполнить ! DefinePropertyOrThrow(obj, "length", PropertyDescriptor {[[Value]]: 𝔽(len), [[Writable]]: true, [[Enumerable]]: false, [[Configurable]]: true}).
17. Пусть mappedNames будет новым пустым Списком.
18. Установите для index значение numberOfParameters - 1.
19. Повторить, пока index ≥ 0,
   а. Пусть name будет parameterNames[index].
   b. Если name не является элементом mappedNames, тогда
      i. Добавьте name как элемент списка mappedNames.
      ii. Если index < len, то
         1. Пусть g будет MakeArgGetter(name, env).
         2. Пусть p будет MakeArgSetter(name, env).
         3. Выполните map.[[DefineOwnProperty]] (! ToString(𝔽(index)), PropertyDescriptor {[[Set]]: p, [[Get]]: g, [[Enumerable]]: false, [[Configurable] ]: true}).
   c. Установить index в index - 1.
20. Выполнить ! DefinePropertyOrThrow(obj@@iterator, PropertyDescriptor { [[Value]]: %Array.prototype.values%, [[Writable]]: true, [[Enumerable]]: false, [[Configurable]]: true }).
21. Выполнить ! DefinePropertyOrThrow(obj, "callee", PropertyDescriptor { [[Value]]: func, [[Writable]]: true, [[Enumerable]]: false, [[Configurable]]: true }).
22. Вернуть obj.

 

MakeArgGetter ( name, env )

Абстрактная операция MakeArgGetter (Создать получателя аргумента) принимает аргументы name (String) и env (Environment Record). Он создает встроенный объект функции, который при выполнении возвращает значение, привязанное к name в env. При вызове она выполняет следующие шаги:

1. Пусть шаги steps будут шагами функции ArgGetter, как указано ниже.
2. Пусть длина length будет количеством необязательных параметров функции ArgGetter, как указано ниже.
3. Пусть getter будет ! CreateBuiltinFunction(stepslength"", « [[Name]], [[Env]] »).
4. Установите getter.[[Name]] на name.
5. Установите getter.[[Env]] в env.
6. Вернуть getter.

Функция ArgGetter — это анонимная встроенная функция с внутренними слотами [[Name]] и [[Env]]. Когда вызывается функция ArgGetter, которая не ожидает аргументов, она выполняет следующие шаги:

1. Пусть f будет активным функциональным объектом.
2. Пусть name будет f.[[Name]].
3. Пусть env будет f.[[Env]].
4. Вернуть env.GetBindingValue(name, false).
Примечание

Функции ArgGetter никогда не доступны напрямую коду ECMAScript.

MakeArgSetter ( name, env )

Абстрактная операция MakeArgSetter (Создать установщика аргумента) принимает аргументы name (String) и env (Environment Record). Она создает встроенный объект функции, который при выполнении устанавливает значение, привязанное к name в env. При вызове она выполняет следующие шаги:

1. Пусть шаги steps будут шагами функции ArgSetter, как указано ниже.
2. Пусть длина length будет количеством необязательных параметров функции ArgSetter, как указано ниже.
3. Пусть setter будет ! CreateBuiltinFunction(stepslength"", « [[Name]], [[Env]] »).
4. Установите setter.[[Name]] на name.
5. Установите setter.[[Env]] на env.
6. Вернуть setter.

Функция ArgSetter — это анонимная встроенная функция с внутренними слотами [[Name]] и [[Env]]. Когда функция ArgSetter вызывается со значением аргумента, она выполняет следующие шаги:

1. Пусть f будет активным функциональным объектом.
2. Пусть name будет f.[[Name]].
3. Пусть env будет f.[[Env]].
4. Вернуть env.SetMutableBinding(name, value, false).
Примечание

Функции ArgSetter никогда не доступны напрямую коду ECMAScript.

 

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

Предыдущий раздел — Экзотические объекты Строк

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