闭包 #
一、闭包概述 #
闭包(Closure)是指函数与其词法环境的组合。闭包允许内部函数访问外部函数的变量,即使外部函数已经执行完毕。
二、词法作用域 #
2.1 作用域链 #
typescript
const globalVar = "global";
function outer() {
const outerVar = "outer";
function inner() {
const innerVar = "inner";
console.log(globalVar); // global
console.log(outerVar); // outer
console.log(innerVar); // inner
}
inner();
}
outer();
2.2 词法绑定 #
函数在定义时(而非调用时)确定其作用域:
typescript
const message = "global";
function print() {
console.log(message);
}
function execute() {
const message = "local";
print(); // 输出 "global",而非 "local"
}
execute();
三、闭包基础 #
3.1 基本示例 #
typescript
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
3.2 变量持久化 #
闭包使变量在函数执行后仍然存在:
typescript
function createGreeter(greeting: string) {
return function(name: string) {
return `${greeting}, ${name}!`;
};
}
const sayHello = createGreeter("Hello");
const sayHi = createGreeter("Hi");
console.log(sayHello("Alice")); // Hello, Alice!
console.log(sayHi("Bob")); // Hi, Bob!
3.3 多个闭包共享变量 #
typescript
function createCounter() {
let count = 0;
return {
increment() {
count++;
return count;
},
decrement() {
count--;
return count;
},
getCount() {
return count;
}
};
}
const counter = createCounter();
console.log(counter.increment()); // 1
console.log(counter.increment()); // 2
console.log(counter.decrement()); // 1
console.log(counter.getCount()); // 1
四、闭包应用场景 #
4.1 数据私有化 #
typescript
function createWallet(initialBalance: number) {
let balance = initialBalance;
return {
deposit(amount: number) {
balance += amount;
return balance;
},
withdraw(amount: number) {
if (amount > balance) {
throw new Error("余额不足");
}
balance -= amount;
return balance;
},
getBalance() {
return balance;
}
};
}
const wallet = createWallet(100);
console.log(wallet.deposit(50)); // 150
console.log(wallet.withdraw(30)); // 120
console.log(wallet.getBalance()); // 120
// wallet.balance = 0; // 错误:无法直接访问
4.2 函数工厂 #
typescript
function createMultiplier(factor: number) {
return (value: number) => value * factor;
}
const double = createMultiplier(2);
const triple = createMultiplier(3);
console.log(double(5)); // 10
console.log(triple(5)); // 15
4.3 配置函数 #
typescript
function createConfig(defaults: Record<string, unknown>) {
let config = { ...defaults };
return {
get(key: string) {
return config[key];
},
set(key: string, value: unknown) {
config[key] = value;
},
getAll() {
return { ...config };
},
reset() {
config = { ...defaults };
}
};
}
const config = createConfig({ host: "localhost", port: 3000 });
console.log(config.get("host")); // localhost
config.set("port", 8080);
console.log(config.getAll()); // { host: "localhost", port: 8080 }
4.4 事件处理器 #
typescript
function createButtonHandler(buttonId: string) {
let clickCount = 0;
return {
handleClick() {
clickCount++;
console.log(`Button ${buttonId} clicked ${clickCount} times`);
},
getClickCount() {
return clickCount;
}
};
}
const handler = createButtonHandler("submit");
handler.handleClick(); // Button submit clicked 1 times
handler.handleClick(); // Button submit clicked 2 times
4.5 延迟执行 #
typescript
function debounce<T extends (...args: unknown[]) => void>(
fn: T,
delay: number
): (...args: Parameters<T>) => void {
let timeoutId: number | undefined;
return function(this: unknown, ...args: Parameters<T>) {
clearTimeout(timeoutId);
timeoutId = setTimeout(() => fn.apply(this, args), delay);
};
}
const debouncedLog = debounce(console.log, 300);
debouncedLog("hello");
debouncedLog("world"); // 只有这个会执行
4.6 节流函数 #
typescript
function throttle<T extends (...args: unknown[]) => void>(
fn: T,
limit: number
): (...args: Parameters<T>) => void {
let inThrottle = false;
return function(this: unknown, ...args: Parameters<T>) {
if (!inThrottle) {
fn.apply(this, args);
inThrottle = true;
setTimeout(() => inThrottle = false, limit);
}
};
}
const throttledLog = throttle(console.log, 1000);
throttledLog("first"); // 执行
throttledLog("second"); // 被节流
4.7 记忆化 #
typescript
function memoize<T, R>(fn: (arg: T) => R): (arg: T) => R {
const cache = new Map<T, R>();
return (arg: T) => {
if (cache.has(arg)) {
console.log("Cache hit");
return cache.get(arg)!;
}
console.log("Cache miss");
const result = fn(arg);
cache.set(arg, result);
return result;
};
}
const expensiveCalculation = memoize((n: number): number => {
console.log("Computing...");
return n * n;
});
console.log(expensiveCalculation(5)); // Computing... 25
console.log(expensiveCalculation(5)); // Cache hit 25
五、循环与闭包 #
5.1 经典问题 #
typescript
// 问题:所有输出都是3
for (var i = 0; i < 3; i++) {
setTimeout(() => {
console.log(i);
}, 100);
}
// 输出:3, 3, 3
5.2 使用let解决 #
typescript
for (let i = 0; i < 3; i++) {
setTimeout(() => {
console.log(i);
}, 100);
}
// 输出:0, 1, 2
5.3 使用IIFE解决 #
typescript
for (var i = 0; i < 3; i++) {
((j) => {
setTimeout(() => {
console.log(j);
}, 100);
})(i);
}
// 输出:0, 1, 2
5.4 使用forEach #
typescript
[0, 1, 2].forEach((i) => {
setTimeout(() => {
console.log(i);
}, 100);
});
// 输出:0, 1, 2
六、闭包与内存 #
6.1 内存占用 #
闭包会保持对外部变量的引用,可能导致内存无法释放:
typescript
function createLargeClosure() {
const largeData = new Array(1000000).fill("data");
return function() {
console.log(largeData.length);
};
}
const fn = createLargeClosure();
// largeData仍然存在于内存中
6.2 手动释放 #
typescript
function createHandler() {
let largeData = new Array(1000000).fill("data");
return {
process() {
console.log(largeData.length);
},
cleanup() {
largeData = null as unknown as string[];
}
};
}
const handler = createHandler();
handler.process();
handler.cleanup(); // 释放内存
6.3 避免不必要的闭包 #
typescript
// 不推荐:不必要的闭包
function processItems(items: number[]) {
return items.map((item) => {
const process = () => item * 2; // 不必要的闭包
return process();
});
}
// 推荐:直接处理
function processItemsBetter(items: number[]) {
return items.map(item => item * 2);
}
七、闭包陷阱 #
7.1 共享变量问题 #
typescript
function createFunctions() {
const funcs: Array<() => number> = [];
for (var i = 0; i < 3; i++) {
funcs.push(() => i);
}
return funcs;
}
const funcs = createFunctions();
funcs.forEach(fn => console.log(fn())); // 3, 3, 3
7.2 this绑定问题 #
typescript
const obj = {
value: 42,
getValue: function() {
return function() {
return this.value; // this不是obj
};
}
};
const fn = obj.getValue();
console.log(fn()); // undefined
// 解决方案:箭头函数或bind
const obj2 = {
value: 42,
getValue: function() {
return () => this.value;
}
};
7.3 循环引用 #
typescript
function createCircular() {
let obj: { ref?: () => void } = {};
obj.ref = function() {
console.log(obj);
};
return obj;
}
// obj和函数相互引用,可能导致内存泄漏
八、实际应用 #
8.1 模块模式 #
typescript
const module = (() => {
let privateVar = 0;
function privateMethod() {
return privateVar;
}
return {
increment() {
privateVar++;
},
getValue() {
return privateMethod();
}
};
})();
module.increment();
console.log(module.getValue()); // 1
8.2 状态管理 #
typescript
function createStore<T>(initialState: T) {
let state = initialState;
const listeners: Array<(state: T) => void> = [];
return {
getState() {
return state;
},
setState(newState: T) {
state = newState;
listeners.forEach(listener => listener(state));
},
subscribe(listener: (state: T) => void) {
listeners.push(listener);
return () => {
const index = listeners.indexOf(listener);
listeners.splice(index, 1);
};
}
};
}
const store = createStore({ count: 0 });
store.subscribe((state) => console.log("State changed:", state));
store.setState({ count: 1 }); // State changed: { count: 1 }
8.3 中间件模式 #
typescript
function createMiddleware() {
const middlewares: Array<(ctx: unknown, next: () => void) => void> = [];
return {
use(middleware: (ctx: unknown, next: () => void) => void) {
middlewares.push(middleware);
},
execute(ctx: unknown) {
let index = 0;
function next() {
const middleware = middlewares[index++];
if (middleware) {
middleware(ctx, next);
}
}
next();
}
};
}
const app = createMiddleware();
app.use((ctx, next) => {
console.log("Middleware 1");
next();
});
app.use((ctx, next) => {
console.log("Middleware 2");
});
app.execute({});
九、总结 #
本章学习了:
- 词法作用域
- 闭包的基本概念
- 闭包的应用场景
- 循环与闭包
- 闭包与内存
- 闭包陷阱
- 实际应用
下一章,我们将学习模块系统。
最后更新:2026-03-28