闭包

闭包

函数 与其 词法作用域 的结合

  • 当一个 内部函数 访问其外部函数作用域中的变量时,即使外部函数已经执行完毕,内部函数仍然保留对外部变量的引用。
  • 闭包的形成是因为函数的作用域链(Scope Chain)在定义时就已经确定,而非执行时。

示例

计数器
1
2
3
4
5
6
7
8
9
10
11
function createCounter() {
let count = 0; // 当createCounter函数执行后本该被销毁
return {
increment: () => count++, // 但函数保留了对count的引用
getCount: () => count,
};
}

const counter = createCounter();
counter.increment();
console.log(counter.getCount()); // 1
函数柯里化

一种函数式编程技术,它将一个多参数函数转换为一系列单参数函数

柯里化可以逐步传递参数,而不是一次性传递所有参数

1
2
3
4
5
6
const add = a => b => c => a + b + c;

const add5 = add(5); // 固定 a = 5
const add5and3 = add5(3); // 固定 b = 3

console.log(add5and3(2)); // 输出: 10 (5 + 3 + 2)

上面的例子中,add5 是一个闭包,它记住了 a = 5,并且可以在后续调用中使用这个值

核心作用

  • 封装私有变量

  • 延长变量生命周期

总结

闭包是指一个函数能够访问并记住其词法作用域中的变量,即使该函数在其作用域外执行。

它的核心原理是函数在定义时会绑定作用域链,使得内部函数可以访问外部函数的变量。闭包的典型应用包括封装私有变量(如计数器)、模块化开发、函数柯里化等。

需要注意的是,闭包可能导致内存泄漏,尤其是当它长期引用不再需要的大对象时。因此,在不需要时应及时解除引用(如将闭包赋值为 null)。此外,当闭包不再被任何地方引用时,其作用域链才会被垃圾回收。避免在频繁调用的函数(如循环体)中创建闭包,可能导致内存累积。

优先使用let定义块级变量,或在闭包中显式传递变量,避免意外共享。合理设计闭包生命周期,及时解除无用引用以优化内存。