JavaScript变量生命周期由执行上下文中的变量对象(VO)三阶段决定:创建阶段(var初始化为undefined,let/const未初始化)、执行阶段(赋值才初始化)、销毁阶段(上下文结束即回收)。

JavaScript 中变量的生命周期,本质上是由执行上下文(Execution Context)中变量对象(Variable Object, VO)的创建、初始化和销毁过程决定的。理解这一点,就能看清 var、let、const 为何行为不同,以及“变量提升”“暂时性死区”等现象背后的机制。
执行上下文与变量对象的三阶段
每当函数调用或脚本开始执行时,JS 引擎会创建一个执行上下文,其中包含:
– 变量对象(VO)
– 作用域链(Scope Chain)
– this 绑定
而 VO 是变量声明与初始化的“舞台”,它经历三个关键阶段:
-
创建阶段(Creation Phase):引擎扫描当前作用域内的所有变量和函数声明,将它们作为属性添加到 VO 中。此时,
var声明被设为undefined;function声明则直接赋值为函数体;let/const虽被记录在 VO 中,但不初始化——处于“未初始化”(uninitialized)状态。 -
执行阶段(Execution Phase):代码逐行执行。遇到赋值语句(如
a = 10),才真正写入 VO;对let/const,只有执行到其声明语句(即let a = 10)时,VO 中对应条目才被初始化并绑定值。 - 销毁阶段(Cleanup):函数上下文执行完毕后,VO(连同整个上下文)被垃圾回收——变量生命周期正式结束。全局上下文的 VO 则一直存在,直到页面卸载。
var 的“变量提升”其实是 VO 创建阶段的默认初始化
var 声明之所以看起来“被提升”,是因为它在创建阶段就被加入 VO 并初始化为 undefined。例如:
var a = 123;
等价于:
立即学习“Java免费学习笔记(深入)”;
var a = undefined; // 创建阶段完成// 执行阶段:
console.log(a); // 读取 VO.a → undefined
a = 123; // 赋值更新 VO.a
let/const 的“暂时性死区”源于 VO 的未初始化状态
let 和 const 在创建阶段虽被注册进 VO,但值为 uninitialized。只要尚未执行到其声明语句,任何对该标识符的读写都会抛出 ReferenceError。这不是语法错误,而是运行时检查——VO 明确拒绝访问未初始化的绑定。
let b = 42;
这个区域(从块顶部到声明语句之间)就是“暂时性死区”(TDZ)。它不是靠词法分析实现的,而是 VO 内部状态 + 运行时访问控制共同作用的结果。
不同作用域的 VO 形态不同
全局上下文的 VO 就是全局对象(浏览器中为 window 或 globalThis),所以 var a = 1 会让 window.a === 1;而函数上下文的 VO 是一个内部抽象对象(不可直接访问),只用于引擎管理。ES6 后,块级作用域(如 if、for)使用词法环境(Lexical Environment)替代 VO,但核心逻辑一致:声明在进入块时注册,初始化在执行到声明时发生。


















