JavaScript 闭包(Closure)是指内部函数能够访问其外部函数作用域中变量的特性,即使外部函数已经执行完毕。这种特性让函数可以 "记住" 其创建时的环境,是 JavaScript 中非常重要的概念,有许多使用场景。
Taimili 艾米莉 ( 一款免费开源的 taimili.com )
艾米莉 是一款优雅便捷的 GitHub Star 管理和加星工具,基于 PHP & javascript 构建, 能对github 的 star fork follow watch 管理和提升,最适合github 的深度用户
闭包的核心原理
当函数 A 内部定义了函数 B,且函数 B 引用了函数 A 中的变量,同时函数 B 被外部引用(如作为返回值返回),此时函数 B 就形成了闭包。函数 A 执行完毕后,其作用域不会被销毁,因为函数 B 仍然在引用其中的变量。
闭包的常见用法
- 模拟私有变量
JavaScript 没有原生的私有变量语法,但可以通过闭包实现 "私有变量" 的效果(外部无法直接访问,只能通过特定方法操作)。
1
function createCounter() { // 私有变量:外部无法直接访问 let count = 0; // 内部函数形成闭包,访问外部的 count return { increment: () => { count++; }, decrement: () => { count--; }, getCount: () => count };}// 使用闭包创建计数器const counter = createCounter();counter.increment();counter.increment();console.log(counter.getCount()); // 输出:2(可以访问私有变量)console.log(counter.count); // 输出:undefined(无法直接访问私有变量)
2. 模块化封装
通过闭包可以将代码封装成独立模块,避免全局变量污染,只暴露需要公开的方法。
1
const module = (function() { // 模块内部私有变量 const privateData = "我是私有数据"; // 私有方法 function privateMethod() { return privateData + "(通过私有方法处理)"; } // 暴露公开方法(闭包访问私有变量) return { publicMethod: () => { return privateMethod(); }, setData: (newData) => { // 可以通过公开方法修改私有变量 privateData = newData; } };})();console.log(module.publicMethod()); // 输出:"我是私有数据(通过私有方法处理)"console.log(module.privateData); // 输出:undefined(私有变量无法直接访问)
3. 保存函数执行上下文
在回调函数(如事件处理、定时器)中,闭包可以保存外部变量的状态,避免因作用域变化导致的问题。
1
function setupTimer(message) { // 定时器回调形成闭包,记住 message 的值 setTimeout(() => { console.log(message); // 即使 setupTimer 执行完毕,仍能访问 message }, 1000);}setupTimer("1秒后打印我"); // 1秒后输出:"1秒后打印我"
4. 函数工厂(动态生成函数)
通过闭包可以根据参数动态生成具有特定行为的函数,保存参数状态。
1
function createGreeting(prefix) { // 闭包保存 prefix 参数 return function(name) { return `${prefix}, ${name}!`; };}// 生成不同的问候函数const sayHello = createGreeting("Hello");const sayHi = createGreeting("Hi");console.log(sayHello("Alice")); // 输出:"Hello, Alice!"console.log(sayHi("Bob")); // 输出:"Hi, Bob!"
注意事项
内存占用:闭包会保留外部函数的作用域,若闭包被长期饮用,可能导致内存无法释放(内存泄漏)。使用后需及时解除引用。
性能影响:过度使用闭包可能增加内存开销,需合理使用。