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

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

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

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

4 ответов


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

в вашем случае, вы определили 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. если код - это код функции, то

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

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

    c. Пусть n быть числом 0.

    d. Для каждой строки argName на имена, в порядке списка

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

    ii. Если n больше argCount, пусть v быть определено иначе v стоимость args.

    раздел III. пусть argAlreadyDeclared быть результатом вызова envхасбиндинг конкретный метод проходя argName как аргумент.

    iv. если argAlreadyDeclared имеет значение false, вызов env’S CreateMutableBinding конкретный метод прохождения argName как аргумент.

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

....

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

    a. Пусть dn быть идентификатор на d.

    b. Пусть varAlreadyDeclared быть результатом вызова envхасбиндинг конкретный проходить метода dn в качестве аргумента.

    c. если varAlreadyDeclared ложно, то

    i. вызов env’S CreateMutableBinding конкретный метод прохождения dn и configurableBindings в качестве аргументов.

    ii. Звоните envметод SetMutableBinding конкретный проходя dn, неопределенному, и строго в качестве аргументов.

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


параметр все еще определен внутри функции, потому что 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);

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

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

оба они находятся в одной области, верно? Я. e как внутри функции check ();

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

так что код, который вы написали equuivalent к

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

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

i.e var a просто игнорируется.

и что вы ожидаете, что var a должен вернуться неопределенным, тогда код будет таким

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

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


потому что 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.