Большинство функций ECMAScript делают «объект аргументов» (arguments object) доступным для своего кода. В зависимости от характеристик определения функции ее объект аргументов является либо «обычным объектом» (ordinary object), либо «экзотическим объектом аргументов» (arguments exotic object). Экзотический объект аргументов — это экзотический объект, свойства индекса массива которого сопоставляются с привязками формальных параметров при вызове связанной с ним функции ECMAScript.
Объект является экзотическим объектом аргументов (arguments exotic object), если его внутренние методы используют следующие реализации, а те, которые здесь не указаны, используют те, что были в разделе 10.1. Эти методы устанавливаются в CreateMappedArgumentsObject.
Хотя CreateUnmappedArgumentsObject сгруппирован в это предложение, он создает обычный объект, а не экзотический объект с аргументами.
Экзотические объекты аргументов имеют те же внутренние слоты, что и обычные объекты. У них также есть внутренний слот [[ParameterMap]]. Объекты обычных аргументов также имеют внутренний слот [[ParameterMap]], значение которого всегда не определено. Для обычных объектов аргументов внутренний слот [[ParameterMap]] используется Object.prototype.toString
(20.1.3.6) только для их идентификации.
Свойства данных с целочисленным индексом экзотического объекта аргументов, значения числового имени которого меньше, чем количество формальных параметров соответствующего объекта функции, изначально совместно используют свои значения с соответствующими привязками аргументов в контексте выполнения функции. Это означает, что изменение свойства изменяет соответствующее значение привязки аргумента и наоборот. Это соответствие нарушается, если такое свойство удаляется и затем переопределяется, или если свойство изменяется на свойство доступа. Если объект аргументов является обычным объектом, значения его свойств являются просто копией аргументов, переданных функции, и нет никакой динамической связи между значениями свойств и значениями формальных параметров.
Объект ParameterMap и значения его свойств используются в качестве устройства для определения соответствия объекта аргументов привязкам аргументов. Объект ParameterMap и объекты, являющиеся значениями его свойств, не наблюдаются напрямую из кода ECMAScript. Реализации ECMAScript не нужно фактически создавать или использовать такие объекты для реализации указанной семантики.
Объекты с обычными аргументами определяют неконфигурируемое свойство доступа с именем «callee» (вызываемый), которое вызывает исключение TypeError при доступе. Свойство «callee» имеет более конкретное значение для экзотических объектов аргументов, которые создаются только для некоторого класса нестрогих функций. Определение этого свойства в обычном варианте существует для того, чтобы гарантировать, что оно не будет определено каким-либо другим образом в соответствии с реализациями ECMAScript.
Реализации экзотических объектов аргументов в ECMAScript исторически содержали свойство доступа с именем «caller» (вызыватель). До ECMAScript 2017 эта спецификация включала определение бросающего свойства «caller» для обычных объектов аргументов. Поскольку реализации больше не содержат это расширение, ECMAScript 2017 отказался от требования к методу доступа «caller«.
- 10.4.4.1 [[GetOwnProperty]] ( P )
- 10.4.4.2 [[DefineOwnProperty]] ( P, Desc )
- 10.4.4.3 [[Get]] ( P, Receiver )
- 10.4.4.4 [[Set]] ( P, V, Receiver )
- 10.4.4.5 [[Delete]] ( P )
- 10.4.4.6 CreateUnmappedArgumentsObject ( argumentsList )
- 10.4.4.7 CreateMappedArgumentsObject ( func, formals, argumentsList, env )
[[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]] ( P, Desc )
Внутренний метод [[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]] ( P, Receiver )
Внутренний метод [[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]] ( P, V, Receiver )
Внутренний метод [[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(steps, length, "", « [[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(steps, length, "", « [[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