什么是变量提升?
变量提升(Hoisting) 是 JavaScript 引擎在代码执行前的一个特殊行为,它会将变量声明和函数声明自动移动到当前作用域的顶部。但需要注意的是,只有声明会被提升,赋值操作不会提升。
核心概念
-
变量声明提升(仅
var
和函数参数):
• 用var
声明的变量会被提升到作用域顶部,但赋值留在原地。• 用
let
和const
声明的变量也会被提升,但不会初始化,导致暂时性死区(TDZ)。 -
函数声明提升:
• 函数声明(非函数表达式)整体被提升,包括函数体。
示例代码
var
的变量提升
javascript
复制
console.log(a); // 输出 undefined(变量声明被提升,但未赋值)
var a = 10;
等价于:
javascript
复制
var a; // 声明提升到顶部
console.log(a); // undefined
a = 10; // 赋值留在原地
let
和const
的暂时性死区
javascript
复制
console.log(b); // 报错:Cannot access 'b' before initialization
let b = 20;
虽然 b
的声明被提升,但在声明前访问会触发错误。
- 函数声明提升
javascript
复制
foo(); // 输出 "Hello"
function foo() {console.log("Hello");
}
等价于:
javascript
复制
function foo() { // 函数声明整体提升console.log("Hello");
}
foo();
注意事项
-
函数表达式不会被提升:
javascript
复制
bar(); // 报错:bar is not a function var bar = function() { /* ... */ };
此时
bar
是变量,提升的是变量声明(值为undefined
)。 -
函数声明优先级高于变量声明:
javascript
复制
console.log(typeof a); // 输出 "function" var a = 3; function a() {}
为什么会有变量提升?
JavaScript 引擎在执行代码前会经历两个阶段:
- 编译阶段:解析代码,提升变量和函数声明。
- 执行阶段:逐行执行代码。
如何避免问题?
- 优先使用
let
和const
:避免var
的隐式全局变量和提升问题。 - 声明变量时先写后用:
javascript
复制
let c = 30; console.log(c); // 正常输出 30
- 使用严格模式(
"use strict"
):禁止意外的全局变量。
总结
• 变量提升是 JavaScript 的历史遗留特性,可能导致意外行为。
• var
会提升声明但初始化为 undefined
,let
/const
存在暂时性死区。
• 函数声明整体提升,函数表达式不会被提升。
• 现代开发中推荐使用 let
/const
和函数表达式(箭头函数)来规避问题。