变量提升与暂时性死区本质是执行上下文创建阶段对声明的差异化处理:var提升并初始化为undefined;let/const提升但不初始化,其声明到初始化前构成TDZ,访问即抛ReferenceError。

函数执行上下文里的变量提升和暂时性死区,本质是 JavaScript 执行上下文创建阶段对不同声明方式的处理差异。不是代码被“移动”了,而是引擎在编译期就为变量和函数分配了内存位置,并按规则初始化。
var 声明:提升 + 初始化为 undefined
在函数执行上下文创建阶段,所有 var 声明会被放入变量对象(VO),并统一初始化为 undefined。因此,在函数体任何位置访问该变量,都不会报错,但值可能是未预期的 undefined。
- 即使
console.log(x)出现在var x = 100之前,也输出undefined - 赋值语句(
x = 100)仍保留在原位置,只在执行阶段运行 - 多个同名
var声明会被合并,不会重复初始化
function 声明:完整提升,优先级高于 var
函数声明不仅声明被提升,整个函数体也被绑定到变量对象中。若与 var 同名,函数声明会覆盖 var 的初始化(哪怕后者写在前面)。
-
foo()可以在function foo(){}之前调用,且正常执行 - 若同时存在
var foo和function foo,函数声明胜出,foo指向函数而非undefined - 函数表达式(
var bar = function(){})不享受此待遇,仅var bar被提升,bar初始为undefined
let / const 声明:提升但不初始化,进入暂时性死区(TDZ)
在函数执行上下文的创建阶段,let 和 const 声明也会被记录到词法环境(LexicalEnvironment)中,但状态标记为 “uninitialized”。从作用域开始到其声明语句之间,就是该变量的暂时性死区。
-
let count;这行代码之前访问count,直接抛出ReferenceError - 哪怕只差一行,比如
console.log(count); let count = 5;,也进 TDZ -
const要求声明即赋值,所以它的 TDZ 范围是从块首到=右侧表达式求值完成前
为什么 TDZ 存在?它和提升不矛盾
TDZ 不是否认提升,而是强调“声明已注册、但尚未准备好使用”。ES6 明确要求引擎在词法绑定阶段区分“已声明未初始化”和“未声明”两种状态,从而避免 var 带来的静默错误和逻辑陷阱。
- 提升的是“声明本身”,不是“值”;TDZ 是对“未初始化状态”的主动拦截
- 它让时序问题暴露得更早——比如闭包捕获、模块加载顺序、类字段初始化等场景
- 在函数执行上下文中,TDZ 表现为对词法环境的严格访问控制,而非变量对象的缺失

















