简介
《Scope & Closures》深入讲解 JavaScript 的作用域机制和闭包,这是 JS 核心概念中的核心。
编译原理
JavaScript 引擎执行代码前会经过编译阶段:
- 词法分析 (Lexing):将代码分解为 token
- 解析 (Parsing):生成 AST(抽象语法树)
- 代码生成:生成可执行代码
理解 LHS 和 RHS 查询
function foo(a) {
console.log(a + b); // b 是 RHS 查询(需要读取值)
b = a; // b 是 LHS 查询(需要赋值)
}
foo(2);
- LHS (Left-Hand Side):找到变量的容器(赋值操作)
- RHS (Right-Hand Side):找到变量的值(读取操作)
作用域链
function outer() {
let a = 1;
function middle() {
let b = 2;
function inner() {
let c = 3;
console.log(a + b + c); // 层层向外查找
}
inner();
}
middle();
}
outer(); // 输出 6
作用域查找顺序:内层 → 外层 → 全局
闭包
什么是闭包?
闭包是指一个函数能够”记住”并访问其定义时所在作用域的变量,即使该函数在定义时的作用域之外执行。
function createCounter() {
let count = 0;
return function() {
count++;
return count;
};
}
const counter = createCounter();
console.log(counter()); // 1
console.log(counter()); // 2
console.log(counter()); // 3
经典案例:定时器
for (var i = 1; i <= 3; i++) {
setTimeout(() => console.log(i), 100);
}
// 输出: 4, 4, 4 (var 是函数作用域,循环结束后 i = 4)
// 解决方式 1: 使用 let
for (let i = 1; i <= 3; i++) {
setTimeout(() => console.log(i), 100);
}
// 输出: 1, 2, 3 (let 是块级作用域,每次循环创建新变量)
// 解决方式 2: 闭包
for (var i = 1; i <= 3; i++) {
((j) => setTimeout(() => console.log(j), 100))(i);
}
经典案例:模块模式
const Module = (function() {
let _count = 0;
return {
getCount: () => _count,
increment: () => _count++,
reset: () => _count = 0
};
})();
Module.getCount(); // 0
Module.increment();
Module.getCount(); // 1
变量提升 (Hoisting)
var 提升
console.log(a); // undefined (不是 ReferenceError!)
var a = 2;
// 相当于:
var a; // 声明提升到顶部
console.log(a); // undefined
a = 2; // 赋值留在原位
let 和 const 提升(暂时性死区)
// console.log(a); // ReferenceError!
let a = 2;
// let 也有提升,但提升后到声明之间的区域叫"暂时性死区"(TDZ)
函数提升
foo(); // "foo"
function foo() {
console.log("foo");
}
// 函数表达式不会提升
// bar(); // ReferenceError!
var bar = function() {
console.log("bar");
};
块级作用域
let
{
let blockVar = "我在块里";
}
// console.log(blockVar); // ReferenceError
const
const PI = 3.14159;
// PI = 3; // TypeError: 赋值常量
// const 对象可以修改属性
const obj = { name: "Lily" };
obj.name = "Rose"; // OK
// obj = {}; // TypeError: 不能重新赋值
小结
- ✅ 理解作用域链的工作原理
- ✅ 掌握闭包的应用场景
- ✅ 理解变量提升机制
- ✅ 优先使用
let和const - ✅ 警惕闭包带来的内存泄漏问题
相关阅读: