Как Javascript объявляет параметры функции?

function func(x = y, y = 2) { 
    return [x, y];
}

func(); // ReferenceError: y is not defined
func(1); // [1, 2]

Как видно из приведенного выше кода, в области параметров функции есть скрытая TDZ, которая объясняет, почему сбой кода ниже:

function func(arg) {
    let arg = 1; // SyntaxError: Identifier 'arg' has already been declared
}

Поэтому параметры функции должны быть объявлены с помощью let, но меня смущает:

function func(arg) {
    var arg = 1;
    console.log(arg); // 1
}

этот код отлично работает.

Почему вы можете обновлять переменные с помощью var? Как Javascript объявляет параметры функции?


изменить: Я точно знаю, что вы не можете использовать let to redeclare variable. Вопрос здесь заключается в том, объявлены ли параметры функции с помощью let, поэтому:

function func(arg) {
    var arg = 1;
}

выглядит следующим образом:

let arg; // arg parameter declares here
var arg = 1; // func body 

и почему это может выполняться без каких-либо исключений?

Ответ 1

имеется скрытая TDZ в области параметров функции

Да, действительно. Посмотрите здесь на несколько примеров.

Как Javascript объявляет параметры функции?

Как параметры - см. здесь для пошагового объяснения. Они не совпадают с let и не похожи на var, они имеют свою собственную семантику. ES6, который представил инициализаторы по умолчанию, дал им те же ограничения TDZ, что и в let, чтобы уловить больше ошибок программиста.

Почему вы можете переопределять переменные с помощью var?

Потому что до ES5 повторное использование переменной не является условием ошибки, и это поведение необходимо сохранить, чтобы не сломать сеть. Его можно было бы ввести только для новых функций, таких как let и const - или списки аргументов, в которых используются инициализаторы по умолчанию, попробуйте function x(bar, bar) {} vs function x(bar, bar=1){}.

Ответ 2

Это необязательно связано с аргументами функции.

Это также вызовет ошибку:

function func() {
    var arg = 1;
    let arg = 2
    console.log(arg); // 1
}

func();

Ответ 3

Причина в том, что это связано с тем, что люди в сообществе JavaScript называют "подъемом", когда вы делаете var arg = 1, который переводится в var arg; arg = 1;, однако, если var уже определен как здесь из-за параметра функции, тогда компилятор пытается быть полезным и игнорирует последующие повторные объявления вместо того, чтобы бросать ошибку... что, вероятно, является неожиданным поведением и не сопровождалось новым объявлением переменной let, однако он должен оставаться там для обратной совместимости.

Ответ 4

let добавлен совсем недавно, и с ним был введен бросок ошибки, который проявляется, когда вы пытаетесь объявить переменную, которая включает let дважды. Этого не происходит с var, который просто заменит старое значение, если только переменная уже не объявлена ​​с помощью let.

function func(arg) {
    let arg = 1; // not ok, because `let` knows that `arg` is being redeclared
}

function func(arg) {
    var arg = 1; // ok, because `var` will just replace the value of `arg`
}

function func() {
    let arg = 0;
    var arg = 1; // not ok, because `let` declared `arg` already
}

Вот ссылка на MDN для, которая объясняет эту функцию.

Ответ 5

Итак var - устаревший синтаксис, и в идеале вы, вероятно, захотите его не использовать.

Вместо использования let для переменных, которые можно переназначить, и const для констант.

var также имеет глобальную область действия, где let и const ограничены областью, в которой они находятся.

Ответ 6

Связывание параметров не точно соответствует тому же поведению, что и те, которые были объявлены с помощью let.

1) Связи параметров создаются до привязок var. var не создает привязки, которые уже существуют, поэтому проблем там нет. let однако создает привязки после var.

2) Существует ранняя ошибка во всех продуктах, которые создают область, в которой она, как правило, не имеет никакого лексического связывания, если уже есть объявление переменной с тем же именем.

Ответ 7

Первый пример не будет вызывать ошибку значением, если аргумент передается на вызов func.

var не имеет той же области, что и let или const.