我听说访问未初始化的let
和const
值可能会导致ReferenceError
,因为存在一个叫做暂时性死区的东西。
什么是暂时性死区?它与作用域和提升有什么关系?在哪些情况下会遇到它?
我听说访问未初始化的let
和const
值可能会导致ReferenceError
,因为存在一个叫做暂时性死区的东西。
什么是暂时性死区?它与作用域和提升有什么关系?在哪些情况下会遇到它?
let
和 const
与 var
相比有两个主要的不同点:
var
的结果为 undefined
;在声明前访问一个 let
或 const
会抛出 ReferenceError
异常:console.log(aVar); // undefined
console.log(aLet); // Causes ReferenceError: Cannot access 'aLet' before initialization
var aVar = 1;
let aLet = 2;
let
声明(以及与之相同的const
声明)可能不会被提升,因为在赋值之前似乎不存在aLet
。let
和const
像var
、class
和function
一样被提升了,但是它们进入作用域和被声明之间有一个时间段,在此期间它们不能被访问。这个时间段就是临时死区(TDZ)。aLet
被声明而不是赋值时,TDZ就结束了。
// console.log(aLet) // Would throw ReferenceError
let aLet;
console.log(aLet); // undefined
aLet = 10;
console.log(aLet); // 10
这个例子展示了let
是被提升的:
let x = "outer value";
(function() {
// Start TDZ for x.
console.log(x);
let x = "inner value"; // Declaration ends TDZ for x.
}());
来源:深入浅出解析时间死区(Temporal Dead Zone)。
在内部作用域中访问x
仍会导致ReferenceError
。如果let
没有被提升,它将记录outer value
。
时间死区是一件好事,因为它有助于突出错误——在声明之前访问值很少是有意的。
时间死区也适用于默认函数参数。参数从左到右进行评估,并且每个参数都在分配之前处于时间死区中:
// b is in TDZ until its value is assigned.
function testDefaults(a = b, b) { }
testDefaults(undefined, 1); // Throws ReferenceError because the evaluation of a reads b before it has been evaluated.
在babel.js转译器中,默认情况下未启用TDZ。打开“高兼容性”模式以在REPL中使用。提供es6.spec.blockScoping
标志,以在CLI或作为库中使用。
建议进一步阅读:TDZ揭秘和深入理解ES6 Let、Const和“时间死区”(TDZ)。
变量提升:
let
、const
和 var
都会被提升。
(意思是它们会被移动到作用域的顶部进行声明。)
初始化:
var
也经历了初始化过程,其值将被初始化为 undefined
。let
、const
没有经历初始化过程,因此它们的值仍然无法访问,尽管已经被声明了。
这就是为什么会进入“暂时性死区”。简而言之:
变量提升过程:
var
、let
、const
初始化过程:var
let
和 const
是块级作用域,而 var
是函数作用域。 - frontendherodk对于 let 和 const 变量,基本上,Temporal Dead Zone 是一个区域
"在您的变量声明之前",
即在这些变量的值无法访问的区域内,将会抛出一个错误。
例如:
let sum = a + 5; //---------
//some other code // | ------> this is TDZ for variable a
// |
console.log(sum) //---------
let a = 5;
上述代码会出现错误。
当我们使用变量'a'的var关键字时,同样的代码将不会产生错误,例如:
var sum = a;
console.log(sum) //prints undefined
var a = 5;
undefined
和5
相加的结果)。变量var a
的声明被提升了,但将a
设置为5的初始化代码并没有。 - traktor