为何变量遮蔽时无法引用原变量?Block A为何触发ReferenceError?
让我来把这两个问题拆解清楚,帮你理解JavaScript变量遮蔽背后的逻辑~
这本质上是**暂时性死区(Temporal Dead Zone,TDZ)**在起作用。当你在一个块级作用域里用let或const声明一个和外层同名的变量时,这个变量的绑定会在作用域创建时就被“提升”了,但它并不会被初始化——从作用域开始到变量声明语句执行前的这段时间,就是这个变量的暂时性死区。
在TDZ内,你根本无法访问这个变量,哪怕外层有同名的变量也不行。因为JavaScript引擎会优先在当前作用域查找变量绑定,一旦当前作用域存在这个变量的声明(哪怕还没初始化),就不会去外层作用域寻找了。这种设计是为了避免变量未初始化就被使用的潜在bug。
先把你的代码再贴出来方便分析:
const something = 'something'; console.log (); try { // Block A { const something = something; } } catch (e) { console.log(e); } console.log (); // Block B { const something = 'somethingElse'; }
代码块A的问题分析
在Block A的{ const something = something; }这句话里:
- 当进入这个块作用域时,
const something的变量绑定就已经存在了(进入TDZ); - 等号右边的
something,JavaScript引擎会先在当前块作用域查找,发现已经有这个变量的绑定了,所以不会去外层找那个已经初始化的something; - 但此时当前作用域的
something还处于暂时性死区,还没有被初始化(要等赋值完成才会初始化),所以尝试访问它就会直接抛出ReferenceError。
代码块B为什么没问题?
Block B里的{ const something = 'somethingElse'; },等号右边是一个字符串字面量,不是对变量的引用。所以JavaScript引擎不需要去查找任何变量绑定,直接把字面量赋值给新声明的something,变量完成初始化后就脱离了TDZ,自然不会报错。
你提到的“这种机制可防止用变量的某个属性来遮蔽该变量本身”,其实就是这个逻辑的延伸——比如如果允许这种写法,有人可能会写出const obj = obj.someProp这样的代码,结果obj还没初始化就被用来访问属性,这显然是错误的,TDZ机制就提前把这种bug拦下来了。
内容的提问来源于stack exchange,提问作者Stephen Carboni

