变量提升仅适用于var,其声明被提升但赋值不提升,访问未初始化的var变量返回undefined;let和const存在暂时性死区(TDZ),在声明前访问会抛出ReferenceError,且TDZ从块级作用域顶部开始生效,与代码是否执行到声明语句无关。

变量提升只发生在 var 声明上
JavaScript 引擎在执行代码前会先进行「词法分析」,对 var 声明的变量做「声明提升(hoisting)」:仅提升声明,不提升赋值。这意味着你能在声明前访问该变量,但值是 undefined。
而 let 和 const 虽然也存在声明提升,但它们被刻意设计为「暂时性死区(Temporal Dead Zone, TDZ)」——从块级作用域开始到实际声明语句之间,任何对该标识符的读写都会抛出 ReferenceError。
let/const 在声明前访问会报 ReferenceError
这是最常踩的坑:以为和 var 一样能“安全”读取,结果直接崩掉。
-
var a = 1;→ 允许console.log(a)在声明前执行,输出undefined -
let b = 2;→console.log(b)在声明前执行,抛出ReferenceError: Cannot access 'b' before initialization -
const c = 3;→ 同样触发ReferenceError,且不能重复赋值
console.log(a); // undefined var a = 1; console.log(b); // ReferenceError! let b = 2;
TDZ 不是语法错误,而是运行时限制
引擎在解析阶段确实已记录 let/const 的声明,但故意禁用访问——这属于执行期检查,不是编译失败。所以:
立即学习“Java免费学习笔记(深入)”;
- 静态工具(如 ESLint)可能无法提前捕获 TDZ 问题
- 函数体内引用外部块中未声明的
let变量,错误位置可能让人困惑 - 条件块中声明
let,哪怕逻辑不会执行到那条语句,只要作用域内有声明,TDZ 就覆盖整个块顶部
if (false) {
let x = 10;
}
console.log(x); // ReferenceError! 即使 if 没执行
const 并不意味着「值不可变」
const 只保证绑定不可重新赋值,不冻结值本身。这点常被误解,尤其对对象或数组:
-
const obj = { a: 1 };→obj = {}报错,但obj.a = 2合法 -
const arr = [];→arr.push(1)合法,arr = [1]报错 - 如需真正不可变,得用
Object.freeze()或结构克隆
TDZ 行为和 let 完全一致,区别仅在于赋值限制。











