Изменение значения параметра функции 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]]

  1. Пусть len будет количеством элементов в аргументах.

  2. Пусть indx= len - 1.

  3. Повторите, пока indx >= 0 , (поэтому приведенный ниже цикл не будет выполняться, если в функцию не переданы аргументы :)

(присваивает объекту аргументов создаваемый, здесь он называется map :)

    1. Добавьте name как элемент списка mappedNames.
    1. Пусть g будет результатом вызова абстрактной операции MakeArgGetter с аргументами name и env.
    1. Пусть p будет результатом вызова абстрактной операции MakeArgSetter с аргументами name и env.
    1. Вызвать внутренний метод [[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; 
}