Изменение значения параметра функции JavaScript с помощью массива arguments не работает
Я изучаю JavaScript и довольно сильно путаюсь с массивом аргументов. Позвольте мне уточнить.
У меня есть функция, которая принимает один аргумент и возвращает его. Когда я передаю параметр и переназначаю его, используя arguments[0] = value
, он обновляет значение.
function a(b) {
arguments[0] = 2;
return b;
}
console.log(a(1)); //returns 2
Ответы
Ответ 1
Присвоение указателям на arguments
изменит значение связанного аргумента (пусть назовем его аргументом n
-th), только если функция была вызвана как минимум с n
аргументами. Числово-индексированные свойства объекта arguments
по существу являются сеттерами (и геттерами):
http://es5.github.io/#x10.6
Курсивом ниже приведены мои комментарии о том, как этот процесс связан с вопросом:
(Позвольте) args
(быть) фактические аргументы, передаваемые внутреннему методу [[Call]]
-
Пусть len
будет количеством элементов в аргументах.
-
Пусть indx
= len - 1
.
-
Повторите, пока indx >= 0
, (поэтому приведенный ниже цикл не будет выполняться, если в функцию не переданы аргументы :)
(присваивает объекту аргументов создаваемый, здесь он называется map
:)
-
- Добавьте
name
как элемент списка mappedNames
.
-
- Пусть
g
будет результатом вызова абстрактной операции MakeArgGetter
с аргументами name
и env
.
-
- Пусть
p
будет результатом вызова абстрактной операции MakeArgSetter
с аргументами name
и env
.
-
- Вызвать внутренний метод [[DefineOwnProperty]] для
map
передавая ToString (indx
), дескриптор свойства {[[Set]]: p
, [[Get]]: g
, [[Configurable]]: true
} и false
качестве аргументов.,
Таким образом, если функция вызывается без аргументов, для arguments[0]
не будет установщика, поэтому ее переназначение не изменит параметр с индексом 0.
То же самое происходит и для других индикаторов - если вы вызываете функцию с 1 параметром, но функция принимает два параметра, присваивание arguments[1]
не изменит второй параметр, потому что для arguments[1]
нет сеттер:
function fn(a, b) {
arguments[1] = 'bar';
console.log(b);
}
fn('foo');
Ответ 2
ECMA 262 9.0 2018 описывает это поведение в 9.4.4 Аргументы Экзотических Объектов с
ПРИМЕЧАНИЕ 1:
Свойства данных с целочисленными индексами экзотического объекта аргументов, числовые значения имен которого меньше числа формальных параметров соответствующего объекта функции, первоначально делят свои значения с соответствующими привязками аргументов в контексте выполнения функции. Это означает, что изменение свойства изменяет соответствующее значение привязки аргумента и наоборот. Это соответствие нарушается, если такое свойство удаляется, а затем переопределяется или если свойство изменяется на свойство доступа. Если объект arguments является обычным объектом, значения его свойств являются просто копией аргументов, передаваемых функции, и динамическая связь между значениями свойств и значениями формальных параметров отсутствует.
Короче,
-
если в 'sloppy mode'
, то все аргументы отображаются на их именованные переменные, если длина соответствует данному параметру, или
-
если в 'strict mode'
привязка теряется после передачи аргументов.
Это доступно только для чтения в более старой версии ECMA 262 7.0 2016. Это описывает это поведение в 9.4.4 Аргументы Экзотические Объекты с
Примечание 1:
Для нестрогих функций целочисленные индексированные свойства данных объекта аргументов, числовые значения имен которых меньше числа формальных параметров соответствующего объекта функции, первоначально делят свои значения с соответствующими привязками аргументов в контексте выполнения функции. Это означает, что изменение свойства изменяет соответствующее значение привязки аргумента и наоборот. Это соответствие нарушается, если такое свойство удаляется, а затем переопределяется или если свойство изменяется на свойство доступа. Для функций строгого режима значения свойств объекта arguments являются просто копией аргументов, передаваемых функции, и динамическая связь между значениями свойств и значениями формальных параметров отсутствует.
Ответ 3
Насколько я понимаю, объект аргументов отслеживает только то, что передается в функцию. Поскольку вы изначально ничего не передавали, b
не связан, и в этот момент arguments
не являются "отслеживающими" b
. Затем вы присваиваете значение инициализированным, но пустым arguments
массива и, наконец, возвращаете b, которое не определено.
Чтобы углубиться в это дальше:
Если нестрогая функция не содержит параметров rest, default или destructured, тогда значения в объекте arguments изменяются синхронно со значениями переменных аргумента. Смотрите код ниже:
function func(a) {
arguments[0] = 99; // updating arguments[0] also updates a
console.log(a);
}
func(10); // 99
а также
function func(a) {
a = 99; // updating a also updates arguments[0]
console.log(arguments[0]);
}
func(10); // 99
Если нестрогая функция содержит параметры rest, default или destructured, значения в объекте arguments не отслеживают значения аргументов. Вместо этого они отражают аргументы, предоставленные при вызове функции:
function func(a = 55) {
arguments[0] = 99; // updating arguments[0] does not also update a
console.log(a);
}
func(10); // 10
а также
function func(a = 55) {
a = 99; // updating a does not also update arguments[0]
console.log(arguments[0]);
}
func(10); // 10
а также
// An untracked default parameter
function func(a = 55) {
console.log(arguments[0]);
}
func(); // undefined
Источник: MDN Web Docs
Ответ 4
Это неопределенное определение значения из спецификации javascript:
примитивное значение, используемое, когда переменной не было присвоено значение.
так что если вы не укажете тип возвращаемого значения функции, он вернет undefined.
так что() и (не определено) это не одно и то же. возвращение неопределенного зависит от того, определен тип возврата или нет.
для более ясного объяснения
Ответ 5
это потому что аргументы это не как массив, это объект с целочисленными индексированными ключами данных и длиной свойства, а если длина равна нулю, это означает, что у вас нет аргументов
function a(b) {
arguments[0] = 2;
console.log(arguments.length)
return b;
}
a(1); // length 1 returns 2
console.log(a()); // length 0 returns undefined
Ответ 6
Когда вы не предоставляете никаких параметров, массив arguments
имеет length
равную 0. Затем вы пытаетесь установить для несуществующего элемента массива значение 2
что приводит к возвращению неопределенного
Вы можете просто проверить это с помощью этого фрагмента:
function a(b){
alert(arguments.length) // It will prompt 0 when calling a() and 1 when calling a(undefined)
arguments[0] = 2;
return b;
}