0%

闭包

闭包的实现

在JavaScript等支持一级函数的语言中,闭包通常是这样实现的:

  1. 函数嵌套:在一个函数内部定义另一个函数。
  2. 内部函数引用外部变量:内部函数访问了外部函数的变量。
  3. 外部函数返回内部函数:当外部函数执行完毕后,返回内部函数,这个内部函数仍然保留了对外部函数作用域的引用。
1
2
3
4
5
6
7
8
9
10
11
12
function outerFunction() {
var outer = 'I am outer';

function innerFunction() {
console.log(outer);
}

return innerFunction;
}

var closure = outerFunction(); // 返回内部函数,创建闭包
closure(); // 输出:I am outer

在这个例子中,innerFunction 是一个闭包,因为它访问了外部函数 outerFunction 的变量 outer。即使 outerFunction 已经执行完毕,但是由于 innerFunction 被返回并且保留了对 outer 的引用,所以 outer 仍然可以被访问。

闭包解决的问题

  1. 缓存:闭包可以使得内部函数记住外部函数的变量,即使外部函数执行完毕后,内部函数依然能够访问这些变量,从而避免重复计算,提高程序的性能。。常用于防抖节流

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    function outer() {
    let counter = 0;
    return function increment() {
    counter++;
    console.log(counter);
    };
    }

    const increment = outer();
    increment(); // 输出: 1
    increment(); // 输出: 2

    即使 outer 执行结束,increment 函数仍然能访问并修改 counter 变量。

  2. 模拟私有变量:在 JavaScript 中没有传统的类和访问修饰符(如 private),闭包可以用于创建私有变量。

  3. 回调函数与异步编程:闭包常用于回调函数和异步操作中,确保函数可以访问外部变量。

    1
    2
    3
    4
    5
    6
    7
    function asyncOperation() {
    let message = "Operation done!";
    setTimeout(function() {
    console.log(message); // 延迟后仍能访问 message
    }, 1000);
    }
    asyncOperation();

闭包的缺陷

  1. 内存泄漏:如果不正确使用闭包,可能会导致内存泄漏。闭包会持有其作用域中的变量,如果不及时释放,可能导致这些变量一直占用内存,尤其是在长生命周期的应用中。

    1
    2
    3
    4
    5
    6
    7
    8
    function outer() {
    let largeData = new Array(1000000).fill('data');
    return function() {
    console.log(largeData[0]);
    };
    }

    const inner = outer();

    这里的 largeData 会一直被闭包引用,即使函数已经执行完毕,导致内存未被释放。