记录:【闭包】

一、闭包

1.1、什么是闭包

闭包是能访问到外部函数作用域中变量的函数

记录:【闭包】_第1张图片

闭包代码示例:

    function outer() {
      let num = 10
      //内部函数要作为返回值返回
      function init() {
        num++  //内部函数引用外部函数outer中的num变量
        console.log('num', num);
      }
      return init
    }
    let result = outer() // 调用 outer 函数,返回一个闭包
    result() // 输出 11
    result() // 输出 12

1.2、词法作用域:

变量的可见性是由它在代码中被声明的位置决定的,即在函数创建时就已经确定了,和调用无关,闭包利用的就是词法作用域

1.3、闭包的生命周期

闭包的生命周期是在其创建时开始,并在不再被引用时结束

闭包的生命周期取决于是否还有对闭包的引用。只要闭包仍然被其他代码、变量或函数引用,它就会一直存在。当没有任何引用指向闭包时,垃圾回收机制将自动回收闭包所占用的内存空间。

如下代码示例,将result设置为null,便解除对闭包的引用

    function outer() {
      let num = 10
      //内部函数要作为返回值返回
      function init() {
        num++  //内部函数引用外部函数outer中的num变量
        console.log('num', num);
      }
      return init
    }
    let result = outer() // 调用 outer 函数,返回一个闭包
    result() // 输出 11,每调用一次num+1

    // 此时,闭包仍然被变量 result 引用,因此它的生命周期还未结束

    result = null; // ⭐⭐解除对闭包的引用

1.4、闭包的使用场景

场景1:封装私有变量

场景2:延迟执行

场景3:模块化

场景4:缓存数据

场景1、封装私有变量

闭包可以创建私有变量,外部无法直接访问或修改,从而保护变量不受外部的干扰。

    function createCounter() {
      let count = 0
      function add() {
        count++
        console.log(count);
      }
      return add
    }
    const counter = createCounter()
    counter() //打印 1
    counter() //打印 2
    counter() //打印 3

场景2、延迟执行

闭包可以在异步操作中用于保存状态或数据,并在需要时执行回调函数。

    function delays(delay) {
      return function () {
        setTimeout(() => {
          console.log(`延迟${delay}`);
        }, delay)
      }
    }
    const delayFunction = delays(2000)
    delayFunction()

场景3、模块化

利用闭包可以创建模块化的代码结构,将相关的函数和数据封装在一个闭包内部,通过返回的公共接口来访问和操作这些内部成员。这种方式可以避免全局命名空间的污染,提高代码的可维护性和重用性。

    const myModule = (function () {
      let count = 0
      function add(num) {
        count += num
      }
      function dec(num) {
        count -= num
      }
      function getCount() {
        return count
      }
      return { add, dec, getCount }
    })();
    myModule.add(2)
    myModule.dec(1)
    console.log(myModule.getCount()); //输出1

场景4、缓存数据

使用闭包可以在函数执行完成后,仍然保持对其词法环境中变量的访问权限。这样可以实现缓存值,避免重复计算或重复访问外部数据。在这个例子中,getName 函数记住了 age 的值,可以在后续调用中使用同一个值而不需要重新计算或获取。

  function bar() {
      let name = 'pig'
      let age = 1
      let innerBar = {
        getName() {
          console.log(age);
          return name
        },
        setName(newName) {
          name = newName
        }
      }
      return innerBar
    }
    const foo = bar()
    console.log(foo.getName()); // 输出 1 pig
    foo.setName('dog')
    console.log(foo.getName()); // 输出 1 dog

1.5、缺点

①内存占用:

使用闭包时,变量会一直存在于内存中,可能造成内存占用过高。如果闭包被滥用,可能导致内存泄漏问题。

②性能消耗:

由于闭包需要记住引用环境,所以在内存中的查找会比较耗时,可能会影响函数的执行效率。


你可能感兴趣的:(javascript,前端,开发语言)