ReferenceError,在外部作用域中声明了"let"变量

geo*_*org 2 javascript ecmascript-6

考虑一下:

'use strict';

{
  let p = 1;
  {
    console.log(p); 
    let p = 2;
  }
}
Run Code Online (Sandbox Code Playgroud)

一种直觉告诉我们它应该记录"1"(因为var必须在重新声明之前保留其旧值).但是,实际结果是ReferenceError.这是为什么?(将基于标准的解释).

请注意我已p在外部范围内声明,因此它在内部块中已知.如果你注释掉这p=2条线,一切都运转正常.

作为验尸记录,虽然这种行为似乎有记录,但它仍然非常违反直觉,参见 这个C代码:

void main() {
  int p = 1;
  {
    printf("%d\n", p); // prints '1'
    int p = 2;
  }
}
Run Code Online (Sandbox Code Playgroud)

还有另外一个JS fuckup特别注意!

Ste*_*han 12

MDN称:

在ECMAScript 2015中,让绑定不受变量提升的约束,这意味着让声明不会移动到当前执行上下文的顶部.在初始化之前引用块中的变量会导致ReferenceError(与使用var声明的变量相反,该变量将具有未定义的值).变量在块的开始处于"临时死区",直到处理初始化为止.

问题是你的let p语句创建了一个新变量,其范围是整个代码块.所以p在console.log(p)中; 是指新创建的变量.

提供了与您的情况类似的示例:

function test(){
   var foo = 33;
   if (true) {
     let foo = (foo + 55); // ReferenceError
   }
}
test();
Run Code Online (Sandbox Code Playgroud)

由于词法作用域,表达式(foo + 55)中的标识符"foo"评估为if块的foo,而不是值为33的上覆变量foo.在那一行中,if块的"foo"已经已经在词法环境中创建,但尚未达到(并终止)其初始化(这是语句本身的一部分):它仍然处于时间死区.