这是我参与8月更文挑战的第6天,活动详情查看:8月更文挑战
前言
let 和 const 相关的考题,若要就 let 和 const 关键字特性本身提问,确实很难考察出候选人的水平。但是,它们背后所牵扯出的变量提升、暂时性死区等知识点,对一些同学来说却具有相当的挑战性——这块知识属于大家多少都听说过、能说上那么两句,但基本没几个人能说清楚的类型。
变量提升
TIP 👉 在 ES2015 之前,JS 引擎用 “var” 这个关键字声明所有的变量。
在 “var” 时代,有一个特别的现象:不管我们的变量声明是写在程序的哪个角落,最后都会被提到作用域的顶端
console.log(num)
var num = 1
这段代码不会报错,反而会输出一个 undefined。这就是因为变量的声明被“提升”了,它等价于这样:
var num;
console.log(num)
num = 1
在函数作用域里,也会有类似的现象
function getNum() {
console.log(num)
var num = 1
}
这里同样输出undefined,这是因为函数内部的变量声明会被提升至函数作用域的顶端。
变量提升的原理
TIP 👉 这和js 编译过程有关。JS也是有编译阶段的,它和传统语言的区别在于,JS不会早早地把编译工作做完,而是一边编译一边执行。简单来说,所有的JS代码片段在执行之前都会被编译,只是这个编译的过程非常短暂(可能就只有几微妙、或者更短的时间),紧接着这段代码就会被执行。
JS 和其他语言一样,都要经历编译和执行阶段。正是在这个短暂的编译阶段里,JS 引擎会搜集所有的变量 声明,并且提前让声明生效。至于剩下的语句,则需要等到执行阶段、等到执行到具体的某一句的时候才会生效。这就是变量提升背后的机制。
被禁用的变量提升
let 和 const 区别于 var 的一个重要特性——它们不存在变量提升。
现在我们把上面例子里的 num 用 let 来声明:
console.log(num)
let num = 1
这样做是因为,早期的声明提升机制,其实容纳了很多程序员的误操作——那些忘记被声明的变量无法在开发阶段被明显地察觉出来,而是以 undefined 这样危险的形式藏匿在你的代码里。为了减少运行时错误,防止暗中使坏的undefined 带来不可预知的问题,ES6 特意将“声明前不可用”这一点做了强约束。
用const声明也一样。
暂时性死区
来看一段代码
var name = '青莲使者'
{
me = 'li'
let me
}
运行结果报错
这是因为 ES6 中有明确的规定:如果区块中存在 let 和 const 命令,这个区块对这些命令声明的变量,从一开始就形成了封闭作用域,如果我们在声明前尝试调用它,就会报错
这一段会报错的危险区域,有一个专属的名字,叫”暂时性死区“。其实暂时性死区的本质:当我们进入当前作用域时,let 或者 const 声明的变量已经存在了——它们只是不允许被获取而已。要想获取他们,必须得等到代码执行到声明的位置。