闭包

75 阅读2分钟

什么是闭包 --- 闭包的概念 (一个不能被回收释放的栈空间,叫闭包)

  • 1、在 JS 忍者秘籍(P90)中对闭包的定义:闭包允许函数访问并操作函数外部的变量。

  • 2、红宝书上对于闭包的定义:闭包是指有权访问另外一个函数作用域中的变量的函数。

  • 3、MDN 对闭包的定义为:闭包是指那些能够访问自由变量的函数。这里的自由变量是外部函数作用域中的变量。

    总结: 闭包是指有权访问另一个函数作用域中变量的函数

基本实现
function makeFunc() {
  const name = "Mozilla";
  function displayName() {
    alert(name);
  }
  return displayName;
}

const myFunc = makeFunc();
myFunc();

从底层看闭包

image.png

闭包的作用

闭包的作用主要有这几点

  • 收敛权限
  • 封装变量
  • 防止变量被污染
 // 不使用闭包进行记数
        // let count  = 1
        // function fun(){
        //     count++
        //     console.log(`函数被调用${count}次`);
        // }
        // fun() // 1
        // fun() // 2 
        // // 如果我进行了修改,那么这个数据将会被污染 
        // count = 1000
        // fun() // 1001
        // count 是全局变量,容易被修改,采用闭包形式就不会出现这种情况

 // 闭包
        function closer() {
            let count = 0
            function fn() {
                count ++
                console.log(`函数被调用${count}次`);
            }
            return fn
        }
        let fn = closer()
        fn()
        count = 1000 // 私有变量无法修改

闭包的应用:实现数据的私有,不会被外部修改

性能考量

会导致内存泄漏

在JavaScript中,闭包会对性能产生影响,特别是在循环中创建闭包时。闭包会保留对其外部变量的引用,这可能导致内存泄漏。例如,在循环中创建闭包可能会导致每次迭代都创建一个新的闭包,从而导致额外的内存占用,特别是在IE8及以下版本中,其垃圾收集器无法清理这些闭包所引用的变量。

解决方法:

避免在循环中创建闭包。

如果需要在循环中使用外部变量,可以将变量的值在循环中保存到局部变量中。

示例代码:
// 不好的示例 - 在循环中创建闭包
for (var i = 0; i < someArray.length; i++) {
    someArray[i].onClick = function() {
        alert(i); // 引用外部变量i
    };
}
 
// 更好的做法 - 将循环中的变量值保存到局部变量中
for (var i = 0; i < someArray.length; i++) {
    var localIndex = i; // 将变量值保存到局部作用域
    someArray[i].onClick = function() {
        alert(localIndex); // 使用局部变量
    };
}

在这个示例中,第一种方法会创建多个闭包,每个闭包都引用外部的i变量,而最后一种方法通过将i的当前值赋给局部变量localIndex,从而避免了闭包引用外部变量的问题。