JS 作用域与提升
理解全局/函数/块作用域和变量提升 · 难度:进阶 · +15XP
JavaScript 作用域与变量提升
作用域(Scope)定义了变量的可访问范围,而变量提升(Hoisting)是 JavaScript 的一种默认行为,在代码执行前将函数和变量声明移动到其作用域的顶部。理解作用域和提升是避免 JavaScript 常见陷阱的关键。
三种作用域
| 作用域类型 | 声明方式 | 作用范围 | 是否提升 |
|---|---|---|---|
| 全局作用域 | 任何函数外声明的变量 | 整个脚本 | 提升 |
| 函数作用域 | var 声明的变量 | 所在函数内部 | 提升(初始化为 undefined) |
| 块级作用域 | let / const | { } 代码块内 | 提升但处于暂时性死区(TDZ) |
var:函数作用域,可重复声明,会提升且初始化为 undefinedlet:块级作用域,不可重复声明,提升但处于 TDZ(访问报错)const:块级作用域,声明时必须赋值,不可重新赋值
变量提升详解
// var 的提升行为
console.log(a); // undefined(a 被提升了,但值未初始化)
var a = 10;
console.log(a); // 10
// 上面代码等价于:
// var a; // 提升声明
// console.log(a); // undefined
// a = 10;
// let/const 的提升与 TDZ(暂时性死区)
// console.log(b); // ReferenceError!TDZ 中不能访问
let b = 20;
console.log(b); // 20
// const 的行为
const c = 30;
// c = 40; // TypeError: Assignment to constant variable
// 函数提升:函数声明整体提升
sayHello(); // "Hello!" — 函数声明整体被提升
function sayHello() { console.log("Hello!"); }
// 函数表达式不提升
// sayHi(); // TypeError: sayHi is not a function
var sayHi = function() { console.log("Hi!"); };
// 等价于 var sayHi; sayHi(); sayHi = function()
作用域链与闭包关系
// 作用域链:内部函数可以访问外部函数的变量
const globalVar = "全局变量";
function outer() {
const outerVar = "外部变量";
function inner() {
const innerVar = "内部变量";
console.log(innerVar); // 访问自身作用域
console.log(outerVar); // 访问外部作用域
console.log(globalVar); // 访问全局作用域
}
inner();
// console.log(innerVar); // ReferenceError(外部无法访问内部)
}
outer();
// 块级作用域:let/const 在 {} 内有效
{
var x = 1;
let y = 2;
const z = 3;
}
console.log(x); // 1(var 没有块级作用域)
// console.log(y); // ReferenceError
// console.log(z); // ReferenceError
// for 循环中的经典问题
for (var i = 0; i < 3; i++) {
setTimeout(() => console.log("var:", i), 100);
} // 输出: 3, 3, 3(共享同一个 i)
for (let j = 0; j < 3; j++) {
setTimeout(() => console.log("let:", j), 100);
} // 输出: 0, 1, 2(每次迭代创建新的绑定)