JavaScript 闭包详解:从原理到实战
闭包是 JavaScript 的基石之一。本文从闭包的定义、核心原理入手,通过数据封装、函数工厂、防抖函数等实战场景,深入讲解闭包的应用。同时分析常见陷阱,帮助你写出更优雅、更安全的 JavaScript 代码。
折
折腾侠
2026/03/24 发布
13约 2 分钟238 字 / 244 词00
JavaScript 闭包详解:从原理到实战
什么是闭包?
闭包是指函数能够记住并访问其定义时所在的词法作用域,即使该函数在其作用域之外执行。
核心原理
JavaScript
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
关键点:INLINE_CODE_0 变量被内部函数引用,即使 INLINE_CODE_1 执行完毕,INLINE_CODE_2 也不会被垃圾回收。
实际应用场景
1. 数据封装与私有变量
JavaScript
function createBankAccount(initialBalance) {
let balance = initialBalance; // 私有
return {
deposit: function(amount) {
balance += amount;
return balance;
},
withdraw: function(amount) {
if (amount > balance) throw new Error("余额不足");
balance -= amount;
return balance;
},
getBalance: function() {
return balance;
}
};
}
const account = createBankAccount(1000);
account.deposit(500); // 1500
account.withdraw(200); // 1300
2. 函数工厂
JavaScript
function createMultiplier(factor) {
return function(number) {
return number * factor;
};
}
const double = createMultiplier(2);
const triple = createMultiplier(3);
console.log(double(5)); // 10
console.log(triple(5)); // 15
3. 防抖函数(实用工具)
JavaScript
function debounce(func, delay) {
let timeoutId;
return function(...args) {
clearTimeout(timeoutId);
timeoutId = setTimeout(() => {
func.apply(this, args);
}, delay);
};
}
// 使用:搜索框输入时延迟发送请求
const searchInput = document.getElementById("search");
searchInput.addEventListener("input", debounce((e) => {
fetch(`/api/search?q=${e.target.value}`);
}, 300));
常见陷阱
JavaScript
// ❌ 错误:循环中的闭包
for (var i = 0; i < 3; i++) {
setTimeout(() => console.log(i), 100);
}
// 输出:3, 3, 3(var 没有块级作用域)
// ✅ 正确:使用 let
for (let i = 0; i < 3; i++) {
setTimeout(() => console.log(i), 100);
}
// 输出:0, 1, 2
总结
| 特性 | 说明 |
|---|---|
| 本质 | 函数 + 词法作用域 |
| 优势 | 数据私有化、状态保持 |
| 注意 | 避免内存泄漏,及时清理引用 |
| 适用 | 模块化、回调、事件处理 |
闭包是 JavaScript 的基石之一,掌握它能让你写出更优雅、更安全的代码。