Round 1
- 我现在把所有东西都注释掉,改成这样
function a() {
return inner;
let inner;
}
返回什么?- 那就应该 undefined 了,反正后面不执行
自信的不行,出了门掏出全世界最牛逼的千元机坚果 Pro 2S,验证了一下。
inner is not defined
确实是不执行,但好像不是 undefined
啊╭(*゚Д゚*)╮
Round 2
- 如果改成这样呢
function a() {
function inner() {}
return inner;
let inner;
}
返回什么?- 返回方法
自信的不行,同样用全世界最牛逼的千元机坚果 Pro 2S,验证了一下。
Identifier ‘inner’ has already been declared
(゚Д゚≡゚д゚)!? 你在返回你🐴呢?
Why?
原本我以为只有 var
会变量提升,实际上错了,var/let/const
都会。
var
和 let
在某种时候是相似的,他们都会提升,但 let
少了初始化的过程。MDN 对 let
死区是这么解释的
在 ECMAScript 2015 中,let 绑定不受变量提升的约束,这意味着 let 声明不会被提升到当前执行上下文的顶部。在块中的变量初始化之前,引用它将会导致 ReferenceError(而使用 var 声明变量则恰恰相反,该变量的值是 undefined )。这个变量处于从块开始到 let 初始化处理的”暂存死区“之中。 —— MDN
暂存死区又有这么个说法,用一个代码块解释一下
function () {
a = 'caonima' // 下面有 let,a 直接被该块锁定,这里报错
let a // 到这里才完成初始化,变量开始正常使用,但变量早已提升
console.log(a) // 这里不是 caonima 而是 undefined
a = 'woshinidie'
console.log(a) // woshinidie
}
You-Dont-Know-JS#767 讨论了这个问题, creeperyang 总结了四点
- Hoisting includes both declare and initialize.
- Only initialized variable can be used in a scope.
- var do both declare and initialize, the two cannot be split for var.
- let do firstly declare in the top of the scope, and do initialize when encounter the let xxx statements.
—— @creeperyang
另外,方应杭在知乎专栏的文章《我用了两个月的时间才理解 let》也总结出
- let 的「创建」过程被提升了,但是初始化没有提升。
- var 的「创建」和「初始化」都被提升了。
- function 的「创建」「初始化」和「赋值」都被提升了。
—— @方应杭
理论上 const
应该是 let
的不可修改版本,所以应该是类似的。但也仅限提升原理相同,因为 const
只能初始化时赋值一次。
不过,阮一峰的《ECMAScript 6 入门》是什么意思?在 let 有单独一小节讲 不存在变量提升,虽然后面解释了暂时性死区,但……
总结:被安排明白了。根据 @Ahonn 所说,这个问题在高程有讲过,书读少了读少了
(最后感谢所有被引用的文章和作者,谢谢。)