变量提升本质是声明在编译阶段被提前注册而非代码移动,var声明仅提升声明并初始化为undefined,let/const存在暂时性死区(tdz)不可访问,函数声明整体提升而函数表达式仅变量名提升。

变量提升在 JavaScript 中不是“代码被移动”,而是声明在编译阶段被提前注册到当前作用域的内存空间中。它的表现因作用域类型和声明方式(var、let、const、函数声明)而异,核心差异在于“是否初始化”和“能否访问”。
函数作用域中 var 声明:声明提升,值为 undefined
var 在函数内声明时,声明会被提升到函数顶部,但赋值保留在原位置。此时变量已存在,但尚未初始化,访问即得 undefined。
- 例如:console.log(a); var a = 123; 等价于 var a; console.log(a); a = 123;
- 若外部同名变量被内部
var声明覆盖,会形成遮蔽(shadowing),外部变量不可见 - 注意:即使声明与赋值写在同一行(
var b = 456;),也只有var b部分被提升
全局作用域中 var 声明:提升至全局顶部,不影响外部访问
全局 var 变量也会被提升,但由于没有嵌套干扰,其行为更直观:
-
console.log(c); var c = 789; 输出
undefined,而非报错 - 该变量会成为全局对象(如浏览器中的
window.c)的属性 - 未加
var的赋值(如d = 100;)不会被提升,且可能意外创建全局属性
块级作用域中 let/const:不提升初始化,进入暂时性死区(TDZ)
let 和 const 声明虽有“语法提升”,但不会被初始化。在声明语句执行前访问它们,会直接抛出 ReferenceError。
- 例如:console.log(e); let e = 'hello'; → 报错,不是
undefined - TDZ 范围从块开头起,到声明语句执行完毕止;
if、for、{}内都适用 -
const还要求必须在声明时初始化,否则语法错误
函数声明 vs 函数表达式:整体提升与部分提升
函数声明(function foo() {...})会被完整提升——声明和定义一起到作用域顶部,可前置调用。
- foo(); function foo() { console.log('ok'); } → 正常输出
- 函数表达式(
var bar = function() {...};)按var规则处理:仅var bar提升,bar值为undefined,调用报TypeError - 箭头函数和
class声明也遵循let规则,存在 TDZ











