[路飞]每日一答:let 是否会造成变量提升?(暂时性死区的坑)

416 阅读2分钟

let 是否会造成变量提升

导语

这里的答案一定是否定的,因为我们都知道,只有var会产生变量提升的情况,let是不会产生变量提升的,那么为什么会提出这样的问题呢?我们来看一下下面的代码:

let a = 'a'
function log() {
  console.log(a) // a
}
log()

根据作用域链的规则,在 log函数下,找不到变量a,就会去外部作用域查找,所以打印的是全局作用域下的 a

稍微修改一下:

let a = 'a'
function log() {
  console.log(a)
  let a = 'b'

}

log()

这里的运行结果是: ReferenceError: a is not defined

这里是报错了,原因是在 log函数里面 a 没有被定义,很显然他访问的是当前作用域下的变量a。其实到了这里才是本问题所要问的核心:既然 let 没有变量提升的作用,那么为什么我在函数的最后使用 let,为什么没有使用全局作用域下的 a而是使用了当前作用域下的a呢?

暂时性死区

此时要引入一个新的概念,叫做:“暂时性死区”。

什么是暂时性死区?

在代码块内,使用let命令声明变量之前,该变量都是不可用的。这在语法上,称为“暂时性死区”(temporal dead zone,简称 TDZ)。

那么造成暂时性死区的原因是什么呢?

首先我们要理解,在JS中变量都是词法作用域的,也就是说变量的作用域在编译的第一个阶段“词法阶段”就已经被确定好了。

在本实例中,变量a的作用域,一个是全局作用域,另一个是函数作用域,已经被确定。也就是说函数内部的a此时已经确定为函数内部的作用域。

在执行阶段时,根据作用域链原则,函数内部会先寻找函数内部的作用域变量, 既然a在函数中已经被确定,那么就不会向全局作用域去寻找a了。默认函数内部a是已经定义的。但函数顺序执行的时候,访问a的同时并没有在访问之前声明a,也就是树在当前作用域下,没有找到a的生命和定义,就会出现 为定义的错误了。

总结

let 不会对变量进行提升,但是如果let的定义放在访问之后,会造成函数的暂时性死区,导致变量访问不到而报错。 暂时性死区的本质就是,作用域在编辑阶段就已经被确定好,只要一进入当前作用域,所要使用的变量就已经存在了,但是不可获取,只有等到声明变量的那一行代码出现,才可以获取和使用该变量。