var 声明在预解析阶段被提升并初始化为 undefined,赋值在执行阶段进行;提升仅限于声明所在作用域,同名变量形成遮蔽;let/const 虽提升但处于暂时性死区,访问即报错。

要理解 var 在变量提升阶段的行为,关键不是把它看作“代码被挪到上面”,而是明白 JavaScript 引擎在执行前会先做一次作用域初始化:它扫描整个作用域,把所有 var 声明登记进去,并统一设为 undefined,但跳过赋值语句。
预解析只登记声明,不执行赋值
写 var a = 10,引擎实际拆成两步:
- 预解析阶段:仅执行
var a→ 在当前作用域中创建变量a,值为undefined - 执行阶段:按代码顺序走到
a = 10这一行时,才真正把10赋给a
所以 console.log(a) 出现在声明之前,输出的是 undefined,不是报错,也不是 10——因为变量已存在,只是还没被赋值。
提升范围严格受限于作用域
var 的提升不会跨作用域,只发生在它声明所在的那一层:
立即学习“Java免费学习笔记(深入)”;
- 函数内用
var声明 → 提升到该函数作用域顶部,对外部无影响 - 全局用
var声明 → 提升到全局作用域顶部 - 在
if或for块里用var→ 仍属于外层函数或全局作用域,不构成块级隔离
同名变量会遮蔽,不是“覆盖”
当函数内部用 var 声明一个和外层同名的变量时,它不会修改外层变量,而是创建一个新的局部变量,并在函数作用域顶部被提升:
- 外层
var num = 5和函数内var num = 25是两个独立变量 - 函数开头的
console.log(num)访问的是被提升后的局部num(值为undefined),不是外层那个5 - 这种行为叫“遮蔽(shadowing)”,不是错误,但容易误读
与 let/const 的本质区别
let 和 const 同样会被“提升”,但它们在声明前处于暂时性死区(TDZ):
-
var:提升 + 初始化为undefined→ 可读,值是undefined -
let/const:提升 + 不初始化 → 任何访问(包括typeof)都直接报ReferenceError
这不是“没有提升”,而是提升后拒绝访问——设计上更严格,也更符合直觉。


















