闭包的理解

107 阅读2分钟

闭包

之前总是知道闭包,却没有充分的理解闭包,今天就好好梳理一下闭包的作用和一些弊端。

先来看看MDN闭包的定义

闭包(closure)是一个函数以及其捆绑的周边环境状态(lexical environment,词法环境)的引用的组合。换而言之,闭包让开发者可以从内部函数访问外部函数的作用域。在 JavaScript 中,闭包会随着函数的创建而被同时创建。
​
打重点:内部函数访问外部函数的作用域
举一个栗子:他的作用就好比,你有100圆子(内部函数),你想要买一个东西需要花200圆子,你通过某种方式(访问外部函数的作用域)将100圆子变成了200
function getMoreMoney(multiple){
  const myMoney =100
  return function (){
    return myMoney*multiple
  }
}

闭包的作用

1)缓存状态:闭包可以保持函数执行时的上下文状态,使得函数可以记住之前的操作或状态

function Counting(){
    let count= 1
    return {
        add:function(){
            console.log(++count)
        },
        reduce:function(){
            console.log(--count)
        },
        getValue:function(){
          return count
        }
    }
}
const state = Counting()
state.add()  //2
state.add()   //3
state.reduce() //2

2)封装变量:闭包可以将变量和函数封装在一个作用域内,避免全局命名冲突,并提供私有性,使得变量和函数对外部不可见

function createCounter() {
  let count = 0
​
  return function() {
    count++
    console.log(count)
  };
}
​
const counter = createCounter();
counter() // 输出: 1
counter() // 输出: 2

3)函数工厂:闭包可以用于生成定制的函数,根据不同的配置参数返回不同的函数

function createMultiplier(factor) {
  return function(number) {
    return number * factor;
  };
}
​
const double = createMultiplier(2);
console.log(double(5)); // 输出: 10
​
const triple = createMultiplier(3);
console.log(triple(5)); // 输出: 15

不正当的使用闭包可能会造成内存泄漏

1)内存泄漏:由于闭包会保持对外部变量的引用,如果闭包长时间存在,并且引用的外部变量占用大量内存,就可能导致内存泄漏

function createLeak() {
  const bigArray = new Array(1000000).fill(0);
​
  return function() {
    console.log(bigArray[0]);
  };
}
​
const leakFunc = createLeak();
leakFunc(); // 每次调用都会访问大数组的第一个元素,可能导致内存泄漏

闭包函数中引用的外部变量会被保存在内存中,即使函数执行完毕,这些变量也不会被释放。如果闭包函数长时间存在,并且引用的外部变量占用大量内存,就会导致内存泄漏。

为避免闭包造成内存泄漏,在不再需要使用闭包时,确保将其置为 null 或者解除所有对闭包函数的引用,以便让垃圾回收机制回收相关资源(这个过程叫做GC)

function createLeak() {
  const bigArray = new Array(1000000).fill(0);
​
  return function() {
    console.log(bigArray[0]);
  };
}
​
const leakFunc = createLeak();
leakFunc(); // 每次调用都会访问大数组的第一个元素,可能导致内存泄漏
​
leakFunc = null //手动置空,避免内存泄漏