变量提升是JavaScript引擎在创建阶段将var和function声明提升至作用域顶部,但不提升赋值;let/const虽声明提升却不初始化,导致TDZ内访问报错。

变量提升到底是什么?
变量提升(Hoisting)不是“代码被移动了”,而是 JavaScript 引擎在执行前的「创建阶段」把声明收集到作用域顶部的行为。关键在于:只提升 var 和 function 的声明,不提升赋值;而 let 和 const 虽然也“提升声明”,但不会初始化——这就引出了「暂时性死区」(TDZ)。
var 提升:能访问但值是 undefined
这是最常踩坑的地方:你以为没声明就不能用,结果它默默返回 undefined,还不会报错,导致逻辑出错却难定位。
console.log(a); // undefined(不报错) vara= 10;
- 引擎实际做了:
var a;提升到作用域顶部,初始值为undefined - 赋值
a = 10仍留在原位置,执行时才发生 - 在函数内、
if块里、循环中都一样——只要在同一个函数作用域,就可提前读取
let 提升:一碰就报错的“禁区”
let 变量在声明语句执行前处于「暂时性死区」(TDZ),任何读写操作都会触发 ReferenceError。这不是 bug,是设计来强制你写更安全代码的机制。
console.log(b); // ReferenceError: Cannot access 'b' before initialization letb= 20;
- 声明确实被提升了(否则语法解析就会失败),但引擎拒绝让你在
let b = ...执行前触碰它 - TDZ 范围从块开头开始,直到声明语句执行完毕(包括
for (let i...)循环头部) - 常见误判:“let 没有提升”——错。它有提升,只是不初始化,且严格限制访问时机
为什么这个区别在真实项目里要命?
很多线上 bug 来自对提升行为的误判,尤其在条件分支、模块加载顺序、或与 typeof 配合时:
-
var下的typeof x永远不会报错(返回"undefined"),容易掩盖未定义问题 -
let下的typeof x在 TDZ 内直接报错,反而暴露了依赖顺序问题 - ES6+ 模块中,顶层
let声明不会挂载到window,而var会——跨脚本调试时变量“突然消失”往往源于此 - Vue/React 组件中若用
var声明响应式数据,可能因提升导致初始化时机错乱;let则让作用域和生命周期更可控
真正要注意的不是“记住了区别”,而是:只要没显式写 var,就别假设变量能在声明前安全使用——哪怕它看起来“应该存在”。










