let/const的暂时性死区

暂时性死区的表现

if (true) {
    console.log(value);//VM58:2 Uncaught ReferenceError: Cannot access 'value' before initialization
    let value = 1;
}

进入当前作用域,在变量声明之前访问变量,是无法访问到的。
这是由于let/const没有变量提升(提升到作用域顶部),因此通过let/const定义的变量不会被提升到作用域顶部——也就是此时的块级作用域,因此在声明之前无法访问。
但是为什么报错信息是“Cannot access 'value' before initialization”,而不是我们常见的“value is not defined”呢,这2者有啥区别?
比如以下代码,由于块级作用域,外部是没有value声明的,所以会报错“value is not defined”

if (false) {
    let value = 1;
}
console.log(value);//Uncaught ReferenceError: value is not defined

原因排查

我们通过控制台的作用域来看看

if (true) {
	debugger
    let value = 1;
}


从上图可以看到,控制台的Block作用域里value已经存在了,说明value肯定是被定义了,因此肯定不会报错“value is not defined”,但是又不法访问,原因是当前时刻为“before initialization”。
那也就是“defined”和“initialization”是有区别的?

我这样理解

为了理解以上现象,
参考文章我用了两个月的时间才理解 let,我们可以把 JS 变量分为「创建create、初始化initialize 和赋值assign」3个步骤。

var 声明的「创建、初始化和赋值」过程

if (true) {
    console.log(x, y) // undefined,undefined
    var x = 1
    var y = 2
}

执行上述代码时,会有如下步骤:

  • 找到代码块中所有用 var 声明的变量,在这个环境中「创建」这些变量(即 x 和 y)。
  • 将这些变量「初始化」为 undefined。
  • 开始执行代码
    x = 1 将 x 变量「赋值」为 1
    y = 2 将 y 变量「赋值」为 2
    也就是var在执行赋值操作之前,就将「创建变量,并将其初始化为 undefined」。因此通过var声明变量之前,在同一作用域下访问变量,得到的是undefined。

let 声明的「创建、初始化和赋值」过程

if (true) {
    console.log(x, y) // Cannot access 'value' before initialization
    let x = 1
    let y = 2
}
  • 找到所有用 let 声明的变量,在环境中「创建」这些变量
  • 开始执行代码(注意现在还没有初始化)
  • 执行let x = 1,将 x 「初始化」,并「赋值」为 1(let x 实现初始化,x = 1实现赋值)
  • 对let y = 2实现相同的步骤

无变量提升

从以上分析来看,

  • 我们平常所说的“变量提升“其实是指将「创建」和「初始化」这2个步骤都提升了
  • var存在变量提升,因为其同时提升了「创建」和「初始化」
  • let/const不存在变量提升,实际上是因为let/const只提升了「创建」,而没有提升「初始化」

同时,上面的报错也很好理解了:

  • “value is not defined”是因为变量没有「创建」
  • “Cannot access 'value' before initialization”是「创建」了变量,但没「初始化」

因此,所谓暂时性死区,就是不能在初始化之前使用变量。

需要暂时性死区的原因

ES6增加暂时性死区这一特性,主要是为了减少运行时错误,防止声明之前就使用
但是为什么不直接将「创建」过程也不提升呢?
我的理解是由于js是静态作用域,在代码编译的时候就会去分析各作用域的变量对象,因此「创建」过程一定是在代码执行前完成,也就是一定会被提升,那为了防止大家在声明之前就使用,就在「初始化」上做文章了,没有讲「初始化」不提升,这样就不能在声明之前使用了。

参考:

我用了两个月的时间才理解 let

阮一峰《ES6标准入门》

posted @ 2020-02-26 22:26  小丸子的城堡  阅读(2388)  评论(0编辑  收藏  举报