var变量提升导致声明前访问输出undefined而非报错,且无块级作用域;let/const引入暂时性死区(TDZ)并具块级作用域,强制暴露逻辑错误。

为什么 var 的变量提升总让你调试到凌晨
因为 var 声明的变量会在作用域顶部被“提升”并初始化为 undefined,但赋值不会提升。这导致你写 console.log(a) 在声明前不报错却输出 undefined,而实际想捕获的是“未声明就使用”的逻辑错误。更糟的是,var 没有块级作用域,for 循环里的 var i 会泄漏到整个函数作用域,造成闭包中所有回调共享同一个 i。
let 和 const 怎么堵住这个漏洞
它们都遵循“暂时性死区(TDZ)”规则:从块级作用域开始到声明语句执行前,变量不可访问,访问直接抛 ReferenceError。这不是语法糖,是引擎强制的时序约束。
-
let用于后续会重新赋值的变量,比如循环计数器、临时中间值 -
const用于声明后不再指向新值的变量——注意:对象/数组本身可修改,只是引用地址不能变 - 两者都绑定到最近的
{}块,if、for、try内声明的变量出块即销毁
常见误用场景与修复对照
下面这些写法在 var 下看似能跑,换成 let/const 后立刻暴露问题:
- 在
if块外读取if内用let声明的变量 → 报ReferenceError,说明逻辑依赖了意外泄漏的变量 - 把
const user = { name: 'a' }后又写user = { name: 'b' }→ 报TypeError: Assignment to constant variable,提醒你该用let或只改属性user.name = 'b' -
for (let i = 0; i console.log(i), 0)输出0 1 2;若误写成for (var i = 0; ...)则输出3 3 3
迁移时最易忽略的三个细节
不是把所有 var 替换为 const 就安全了:
- 函数参数不能用
const声明,它本身就是块级绑定的,直接保持function fn(x) { ... }即可 - 全局作用域下用
let/const声明的变量不会挂到window上(var会),依赖window.xxx访问的代码要同步改 -
typeof检测未声明变量时,var返回"undefined",let/const在 TDZ 内直接报错,别在死区里写typeof xxx === 'undefined'
var 长期掩盖的设计债务。

















