Skip to content

闭包

以下是关于闭包的详细解析及典型应用场景示例:

一、闭包核心概念

闭包 = 函数 + 其创建时的词法环境

当函数能记住并访问其所在的词法作用域(即使函数在其作用域外执行),就形成了闭包。

二、典型闭包场景

1. 计数器(状态保持)

javascript
function createCounter() {
  let count = 0; // 被闭包保护的变量
  return {
    increment: () => ++count,
    getCount: () => count
  };
}

const counter = createCounter();
counter.increment(); // 1
counter.getCount();  // 1

闭包特征:increment 和 getCount 函数持续访问父作用域的 count

2. 私有变量(数据封装)

javascript
function createPerson(name) {
  let _age = 0; // 私有变量
  
  return {
    getName: () => name,
    setAge: (age) => _age = age,
    getInfo: () => `${name}(${_age})`
  };
}

const person = createPerson('Alice');
person.setAge(25);
person.getInfo(); // "Alice(25)"

闭包作用:隐藏实现细节,防止直接修改 _age

3. 模块化开发

javascript
const calculator = (() => {
  let memory = 0; // 模块私有状态
  
  return {
    add: (a, b) => {
      memory = a + b;
      return memory;
    },
    getMemory: () => memory
  };
})();

calculator.add(2,3); // 5
calculator.getMemory(); // 5

设计模式:IIFE + 闭包 实现模块化

4. 事件处理(状态捕获)

html
<button id="btn">Click 0</button>

<script>
function setupCounter() {
  let count = 0;
  const btn = document.getElementById('btn');
  
  btn.addEventListener('click', () => {
    btn.textContent = `Click ${++count}`; 
  });
}
setupCounter();
</script>

闭包价值:事件回调函数持续访问外部作用域的 count

5. 函数柯里化(严格分解为单参数链)

javascript
function multiply(a) {
  return (b) => a * b; // 闭包保留a的值
}

const double = multiply(2);
double(5); // 10

应用场景:参数预置、函数组合

6. 循环陷阱与解决方案

  • 问题代码:
javascript
for (var i = 0; i < 5; i++) {
  setTimeout(() => {
    console.log(i); // 输出5个5
  }, 100);
}
  • 闭包解决方案:
javascript
for (let i = 0; i < 5; i++) { // let 块级作用域
  setTimeout(() => {
    console.log(i); // 0,1,2,3,4
  }, 100);
}

// 或使用IIFE
for (var i = 0; i < 5; i++) {
  ((j) => {
    setTimeout(() => console.log(j), 100);
  })(i);
}

三、闭包内存管理

特性说明
内存保留闭包变量不会自动回收
释放条件当闭包函数不再被引用时
常见泄漏场景DOM事件未解绑、全局变量引用

四、闭包优缺点分析

  • 优点:
  1. 实现私有变量
  2. 保持状态持久化
  3. 支持函数式编程范式
  • 缺点:
  1. 过度使用可能导致内存占用过高
  2. 不当使用可能引发内存泄漏
  3. 调试复杂度增加(难以追踪闭包变量)

五、现代JS优化

  • WeakMap:替代传统闭包存储大对象
javascript
const privateData = new WeakMap();

function MyClass() {
  privateData.set(this, { secret: 42 });
}

通过理解这些典型场景,可以更好地把握闭包在工程实践中的应用边界。

Last updated: