Двойное объявление let: Как работает подъем для циклов? - PullRequest
0 голосов
/ 24 июня 2018

Учитывая следующий упрощенный код, почему я получаю ReferenceError?

    function foo(n){
        for (let i = 0; i < n; i++) {       
            console.log(i);
            let i = 10;
        }
    }

    foo(4);

// OUTPUT: ReferenceError: i is not defined

let переменные должны быть выведены как все другие типы объявления.Следовательно, в этом коде i объявляется дважды.Во-первых, в инициализации close и во-вторых в самом цикле for.

Почему этот вывод i is not defined вместо Identifier 'i' has already been declared.

Как JS читает приведенный выше код?

Ответы [ 3 ]

0 голосов
/ 24 июня 2018

let переменные должны быть подняты как все другие типы объявления.

let переменные не подняты, в отличие от var переменных иобъявления функций и классов.const переменные одинаковы.

Переменная не существует, пока вы не достигнете строки, где она объявлена.

Однако , вы не можете получить доступ к переменнойв соответствующей области, пока вы не достигнете декларацииЭто несколько бесполезно известно как временная мертвая зона .( Полезный блог 2ality )

Это полезно, поскольку доступ к переменной до ее объявления почти всегда является ошибкой.Или, по крайней мере, это сбивает с толку и приведет к ошибкам при рефакторинге.

function foo(n){
    for (let i = 0; i < n; i++) {       
        // i cannot be accessed
        let i = 10;
        // i is set to 10
    }
}

foo(4);

Что касается того, почему это не ошибка "идентификатор уже объявлен", область действия переменной, объявленной вЗаголовок цикла for является отдельной переменной от объявленной в блоке.По сути, в этом коде три области действия: внешняя, начальная в заголовке цикла for и начальная в блоке, окруженном {}.

0 голосов
/ 24 июня 2018

Что происходит ниже, так это то, что JavaScript видит два разных уровня области видимости блока внутри одного и того же цикла for.

Первый объявляется во время предложения инициализации цикла (let i = 0;), второй внутри цикласам по себе.

Вот что происходит при первом запуске кода:

  • let в предложении инициализации : i = 0;
  • let внутри цикл for: i is set to undefined

enter image description here

Когда дляхиты цикла console.log(i) находят объявление let i внутри цикла, которое переопределяет ранее объявленное и присвоенное let i (в предложении инициализации.

, так как для каждого подъема let и constобъявленный, но не инициализированный (как undefined), он вызывает ReferenceError.

0 голосов
/ 24 июня 2018

Согласно MDN:

function test(){
  var foo = 33;
  if (true) {
   let foo = (foo + 55); // ReferenceError
  }
}
test();

Из-за лексической области видимости идентификатор "foo" внутри выражения (foo + 55) оценивается как foo блока if, а не как выходящая переменная fooсо значением 33. В этой же строке «foo» блока if уже создан в лексической среде, но еще не достиг (и не завершил) своей инициализации (которая является частью самого оператора): он все еще находится ввременная мертвая зона.

Это означает, что если переменная цикла "read" в вашем примере (console.log в вашем случае, вы не можете присвоить ей то же имя var, что и в«мертвая зона»

MDN ref: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/let (ниже временная мертвая зона )

...