ES6/Node中的词法范围

bif*_*kin 0 javascript scoping lexical node.js ecmascript-6

我试图理解ES6词法范围(使用节点运行时).考虑以下:

'use strict';
let x = 10;
function f() {
   console.log(x);
   console.log(y); // This should crash
}

let y = 5;
f();
Run Code Online (Sandbox Code Playgroud)

从O'Reilly的书"学习Javascript"中解释:

词法作用域意味着您定义函数的范围内的任何变量(与您调用它时相反)都在函数的范围内.

但是,当我运行此程序(通过节点)时,它输出:10 5

是不是调用console.log(y)打破了这里的词法范围规则?如果没有,为什么不呢?

编辑:为了将来参考,似乎教科书的作者(Learning Javascript 3rd Edition O'Reilly)最近在"已确认的勘误表"中将此示例列为错误.在http://www.oreilly.com/catalog/errata.csp?isbn=0636920035534

nil*_*ils 5

正如Benjamin Gruenbaum所提到的那样,letconst没有提升.

作为事实上,也有适用于新的规则letconst,如...

时间死区

现在,如果这些是var声明,一切都会很清楚.但随着letconst,ES6引入了时间死区的新概念.这包括一个新的,微妙的动态.

我们来看看两个例子:

经典起吊可以在这样的例子中起作用:

'use strict';
var x = 10;

console.log(x);
console.log(y); // This should NOT crash

var y = 5;
Run Code Online (Sandbox Code Playgroud)

但是如果我们varlet声明替换声明,它会崩溃:

'use strict';
let x = 10;

console.log(x);
console.log(y); // This crashes: ReferenceError: can't access lexical declaration `y' before initialization

let y = 5;
Run Code Online (Sandbox Code Playgroud)

为什么会崩溃?

因为与var赋值不同,访问let在实际let语句之前使用的变量是无效的(它们位于时间死区).

2.在这种情况下的时间死区

然而,在这种情况下,时间死区不是问题.为什么?

因为虽然我们console.log(y)事先用语句定义了函数,但实际的函数调用和变量访问只发生在代码的末尾.所以变量绑定仅在此时进行评估(再次感谢@BG):

'use strict';
let x = 10;
function f() {
   console.log(x);
   console.log(y); // This should not yet crash
}

let y = 5;
f(); // console.log(y) is only called here
Run Code Online (Sandbox Code Playgroud)

如果你是颠倒的顺序let y = 5;f();,你的代码会崩溃.

  • 发动机不会逐行处理.在开始评估之前,在开始时为给定范围中的每个变量创建绑定,但是对于`let`和`const`,但是绑定保持未初始化,而`var`将绑定初始化为`undefined`.当实际评估`let/const`行时,let/const绑定被初始化,并且尝试访问未初始化的绑定将引发异常. (2认同)