Подтвердить что ты не робот

Почему аргумент функции не перезаписывается при создании переменной с тем же именем внутри функции?

var a = 'why is this not undefined?';
function checkScope(a) {
    var a;
    console.log(a);
}
checkScope(a);

Javascript - это функциональный язык интерфейса, верно? Когда я объявляю новую переменную только внутри функции, которая использует то же имя, что и функциональный аргумент, почему новая определенная переменная все еще содержит те же данные, что и аргумент?

Я думал, что это должно быть undefined?

4b9b3361

Ответ 1

var a; - фактически оператор объявления переменной. Когда функция определена, все объявленные в ней переменные обрабатываются до выполнения кода, поэтому вы можете использовать переменные еще до того, как фактическая строка объявления будет запущена во время выполнения. Это называется var hoisting. Таким образом, независимо от того, сколько раз вы объявляете переменную, переменная объявляется только один раз.

В вашем случае вы определили a как один из параметров функции, который привязан к текущей функции. И затем вы объявляете переменную с тем же именем. Поскольку a уже объявлен в функции, как один из параметров, объявление var a; будет проигнорировано.

Вот почему вы получаете why is this not undefined? в консоли.

Вместо var a;, скажем, у вас есть var a = 1;, в этом случае переменная уже объявлена, но выражение присваивания будет оцениваться во время выполнения, а значение 1 будет присвоено a. Таким образом, console.log будет печатать 1.


Это поведение объясняется в спецификации ECMA Script 5.1, в разделе 10.5 Активация связывания с подписью,

  1. Если код является кодом функции, то

    а. Пусть func - функция, внутренний метод [[Call]] инициировал выполнение кода. Пусть имена будут значением funcs Внутреннее свойство [[FormalParameters]].

    б. Пусть argCount - количество элементов в args.

    с. Пусть n - число 0.

    д. Для каждого String argName в именах, в порядке списка do

          я. Пусть n - текущее значение n плюс 1.

          II. Если n больше argCount, пусть v есть undefined, иначе v - значение n-го элемента args.

          III. Пусть argAlreadyDeclared является результатом вызова envs метода HasBinding, передающего argName в качестве аргумента.

          IV. Если argAlreadyDeclared является ложным, вызовите envs CreateMutableBinding конкретный метод, передающий argName как аргумент.

          v. Вызовите envs SetMutableBinding конкретный метод, передавая argName, v и strict в качестве аргументов.

....

  1. Для каждого VariableDeclaration и VariableDeclarationNoIn d в коде в исходном текстовом порядке выполните

    а. Пусть dn - Идентификатор в d.

    б. Пусть varAlreadyDeclared является результатом вызова envs метода HasBinding, передающего dn в качестве аргумента.

    с. Если varAlreadyDeclared является ложным, то

          я. Вызов envs CreateMutableBinding метод, передающий dn и configurableBindings в качестве аргументов.

          II. Позвонить envs SetMutableBinding конкретный метод, передающий dn, undefined и строгий как аргументы.

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

Ответ 2

  • вы передаете переменную a в функцию проверки как параметр. function checkScope(a) {

  • внутри функции, которую вы снова пытаетесь объявить var a, var a;

Оба они находятся в пределах одного и того же объема, не так ли? i.e внутри функции check();

И в соответствии с docs, что var a внутри функции - это та же переменная, которую вы передали как параметр, и вы просто используете ее перед объявлением... вы можете сделать это с помощью JS

Итак, код, который вы написали, эквивалентен

var a = 'why is this not undefined?';
function checkScope(a) {

    console.log(a);
}
checkScope(a);

В противном случае var a просто игнорируется.

И что вы ожидаете, что var a должен возвращать undefined, тогда код будет таким:

var a = 'why is this not undefined?';
function checkScope() {
   var a
    console.log(a);
}
checkScope();

На этот раз мы не передаем параметр a функции и в пределах области функции создается новая переменная var a, поэтому она становится undefined

Ответ 3

Параметр все еще определен внутри функции, потому что var a; игнорируется, когда переменная уже определена внутри той же области.

Оператор типа var a; не означает, что переменная создается в этой точке кода. Все объявления переменных подняты вверху области видимости, поэтому вы можете повторно их обновлять столько раз, сколько хотите в области, и они все еще только созданный один раз.

Если объявление имеет назначение, как, например, var a = 2;, назначение происходит там, где оператор находится в коде, независимо от того, игнорируется ли объявление или нет.

Пример:

function check(a) {
  // both a and b exist here
  document.write('a = ' + a + ', b = ' + b + '<br>');
  var b = 1;
  document.write('a = ' + a + ', b = ' + b + '<br>');
  var a = 2; // not recreated, but assigned
  document.write('a = ' + a + ', b = ' + b + '<br>');
}

check(42);

Ответ 4

Поскольку JavaScript игнорирует переоценки переменных. Однако, если у вас есть это:

var a = 'why is this not undefined?';
function checkScope(a) {
    var a = 'foo';
    console.log(a);
}
checkScope(a);

Значение a будет перезаписано. Поскольку var a = 'foo'; состоит из объявления переменной (var a;) и присваивания значения (a = 'foo';);

Это поведение описано в MDN docs.