JavaScript变量提升由执行上下文创建阶段决定:var声明提升并初始化为undefined;let/const声明提升但不初始化,存在暂时性死区;函数声明完全提升,函数表达式仅变量名提升。

JavaScript变量提升(Hoisting)不是代码被“移动”了,而是由**执行上下文(Execution Context)的创建阶段**决定的:变量和函数声明会在代码执行前被“登记”进当前作用域的内存空间,但只有声明被提升,赋值仍保留在原位置。
var 声明的提升机制
var 声明会被提升到作用域顶部,并初始化为 undefined。这意味着你可以在声明前访问它,但值是 undefined,不会报错。
例如:
console.log(a); // undefined<br>var a = 10;
立即学习“Java免费学习笔记(深入)”;
这等价于:
var a; // 提升并初始化为 undefined<br>console.log(a); // undefined<br>a = 10; // 赋值保留在原处
注意:重复的 var 声明不会报错,也不会覆盖已有值,只是被忽略。
let 和 const 的“暂时性死区”(TDZ)
let 和 const 声明也会被提升,但**不会初始化**。从作用域开始到声明语句执行前,该变量处于“暂时性死区”,此时访问会抛出 ReferenceError。
例如:
console.log(b); // ReferenceError: Cannot access 'b' before initialization<br>let b = 20;
TDZ 的存在是为了避免在声明前误用变量,也使 const 的“必须初始化”语义更可靠。
函数声明与函数表达式的区别
函数声明(function foo() {...})会被完全提升:函数名和函数体都提前可用。
函数表达式(const foo = function() {...})只提升变量名(如 var 情况),赋值部分不提升;若用 let/const,则受 TDZ 约束。
常见陷阱示例:
foo(); // OK,函数声明已提升<br>function foo() { console.log('hoisted'); }bar(); // TypeError: bar is not a function<br>var bar = function() { console.log('not hoisted'); };baz(); // ReferenceError<br>const baz = () => console.log('in TDZ');
规避提升带来的问题
核心原则:**始终先声明,再使用**。具体可采用以下实践:
- 统一把变量和函数声明放在作用域顶部(尤其对 var,虽非强制但利于理解)
- 优先使用 const 和 let 替代 var,利用 TDZ 捕获早期错误
- 避免在声明前引用任何变量,即使语法允许(如 var 场景)
- 函数尽量用声明形式(需提前调用时),或确保表达式赋值在调用之前
- 启用 ESLint 规则如
no-use-before-define和no-var,强制规范声明顺序










