变量提升
解释 JavaScript 变量提升机制,包括 var 声明提升、函数声明提升和 let/const 暂时性死区。
#tech / dev / frontend
#type / concept
#status / growing
#resource / javascript
#resource / ecmascript
[!info] related notes
- 所属 MOC: ECMAScript MOC, 前端基础 MOC
- 前置概念: ECMAScript 执行上下文
- 并列概念: var / let / const 区别, ECMAScript 闭包
变量提升
这篇笔记回答一个问题:JavaScript 中的变量和函数声明为什么可以在声明之前访问。
一句话定义
变量提升是指 JavaScript 引擎在编译阶段将变量和函数声明移动到当前作用域顶部的行为。
核心机制
变量声明提升
var 声明会被提升到函数或全局作用域顶部,但赋值不会提升。
console.log(a); // undefined(不是 ReferenceError)
var a = 1;
// 等价于:
// var a;
// console.log(a);
// a = 1;
函数声明提升
函数声明(function fn() {})整体提升,包括函数体,可以在声明前调用。
fn(); // "hello"
function fn() {
console.log('hello');
}
函数表达式不提升函数体
函数表达式只提升变量声明,不提升赋值。
fn(); // TypeError: fn is not a function
var fn = function() {
console.log('hello');
};
let / const 的暂时性死区
let 和 const 也会提升,但进入暂时性死区(TDZ),在声明前访问会抛 ReferenceError。
console.log(b); // ReferenceError
let b = 1;
优先级
当 var 和函数声明同名时,函数声明优先。
console.log(typeof fn); // "function"
var fn = 1;
function fn() {}
常见误解
- “变量提升是把代码物理移动了” -> 错误,是引擎在编译阶段的行为,源码不变
- “let / const 没有提升” -> 错误,它们有提升,只是进入 TDZ
- “只有 var 会提升” -> 错误,函数声明也会提升,而且优先级更高
最小例子
// 1. var 提升
console.log(x); // undefined
var x = 10;
// 2. 函数声明提升
sayHi(); // "hi"
function sayHi() { console.log('hi'); }
// 3. 函数表达式不提升
// greet(); // TypeError
var greet = function() { console.log('greet'); };
// 4. let TDZ
// console.log(y); // ReferenceError
let y = 20;