什么是闭包?

149 阅读6分钟

90f3f1b1d0e1f16931854560f3bb99b.jpg

个人简介

今天是2023年 4月21日 学习前端也快一年的时间了 今天决定每天更新一篇常用八股文面试题 这样可以有助于提升自己的总结语言 接下来是我对于闭包的一些理解。

闭包的概念

我认为闭包是层层嵌套的一个函数, 函数包裹着函数, 当内层函数去访问外层函数的变量时 他就形成了闭包, 这个内层函数可以在外层函数被调用之后继续存在, 继续存在就会占用内存,占用内存就会导致内存泄漏,内存泄漏就会引出垃圾回收机制, 这个后面再讲。

怎么运用闭包呢

一、封装私有变量

使用闭包创建一个函数 这个函数可以访问并操作内部的私有变量 下面我用一段代码演示一下

function createCounter() {
  let count = 0;
  return function() {
    count++;
    console.log(count);
  }
}

const counter = createCounter();
counter(); // 输出 1
counter(); // 输出 2
counter(); // 输出 3

在这段代码中 创建了一个createCounter的函数 这个函数返回一个内部函数 这个内部函数可以访问而且可以操作count变量,这个count变量是在createCounter函数作用域定义的 所以它是私有的,不能再外部访问

二、实现模块化

在咱们使用闭包的时候会创建一个模块 这个模块可以封装一组相关的函数和变量,说白了就是这些函数和变量展示给外部环境 这样我们就可以实现更加模块化和可重用代码。

下面我用代码演示一下

const myModule = (function() {
  let count = 0;
  
  function increment() {
    count++;
    console.log(count);
  }
  
  function decrement() {
    count--;
    console.log(count);
  }
  
  return {
    increment,
    decrement
  };
})();

myModule.increment(); // 输出 1
myModule.increment(); // 输出 2
myModule.decrement(); // 输出 1

在上段代码中 我创建了一个立即执行函数 这个函数返回一个对象 这个对象包含两个函数incrementdecrement 这两个函数可以访问并操作count变量,但是这个count变量是在立即执行函数的作用域中定义的, 所以它是私有的,不能从外部访问,通过返回一个包含内部函数的对象,这样就实现一个简单的模块。

三、缓存计算结果

使用闭包可以创建一个函数 这个函数可以缓存并计算结果,方便再后面调用的时候更快的返回结果,帮助咱们优化代码性能

下面我用代码演示一下

function createCache() {
  const cache = {};
  
  return function(key, value) {
    if (value !== undefined) {
      cache[key] = value;
    }
    
    return cache[key];
  };
}

const cache = createCache();
cache('foo', 'bar'); // 返回 'bar'
cache('foo'); // 返回 'bar'(从缓存中获取)

讲述一下闭包的优缺点

优点:

1、封装性:闭包可以将变量和函数封装在一个作用域内,这样就避免了全局变量污染和命名冲突

2、可重用性:闭包可以被多次调用,这样就增加了代码的复用性

3、灵活性:闭包可以访问内部作用域中的变量,从而实现了更加灵活的编程

4、缓存效果:闭包可以用于缓存计算结果,提升代码的性能

缺点:

1、内存泄漏:闭包会占用内存并且可能会导致内存泄漏,所以在使用闭包时需要注意内存管理的问题

2、性能问题:闭包需要访问外部作用域中的变量,因此它的执行速度会比普通函数慢

3、安全问题:闭包可以访问外部作用域的变量,因此可能会被用于实现一些不安全功能 比如窃取私有变量

4、可读性问题:闭包的代码结构比较复杂 所以它会降低代码的可读性和可维护性

vue3中有使用闭包吗

一、setup函数

在vue3中,组件的逻辑代码可以通过setup函数来实现,setup函数是一个接收propscontext参数的函数,它返回一个对象,这个对象包含组件的状态和方法,由于setup函数可以访问外部作用域中的变量,所以它使用了闭包来实现这些功能

二、watch函数

在vue3中 可以使用watch函数来监听组件状态的变化,watch函数接收一个函数和一个选项对象作为参数,这个函数可以访问外部作用域中的变量,所以它使用了闭包来实现这些功能

讲述一下内存泄漏的问题与解决方案

在咱们使用闭包的时候 可能会导致内存泄漏的问题,因为闭包会占用内存,并且可能导致变量无法被垃圾回收,下面是一些解决内存泄漏的方法

1、及时释放闭包

在使用闭包的时候,应该避免长时间持有闭包,避免占用过多的内存,如果不再使用闭包,应该及时释放,方便垃圾回收器可以回收相关内容

2、避免循环使用

闭包中的变量可能会与外部作用域中的变量形成循环引用,从而导致内存泄漏。为了避免这种情况,应该尽可能地避免在闭包中引用外部作用域中的变量,或者使用弱引用来避免循环引用

3、使用模块化的编程风格

使用模块化的编程风格可以帮助我们避免闭包中的变量与全局变量形成循环引用,从而减少内存泄漏的风险。模块化的编程风格可以将变量和函数封装在一个作用域内,从而避免全局变量的污染和命名冲突

4、使用垃圾回收器

现代的编程语言和运行时环境通常都提供了垃圾回收器,可以自动回收不再使用的内存。使用垃圾回收器可以帮助我们避免内存泄漏的问题,但是需要注意垃圾回收器的性能和效率。

结尾心记

我估计就目前的前端市场,应该不会有面试官再会去问这些基础的问题,现在面试都直接问项目相关的问题,所以我有时候也会在质疑自己 写这些东西真的有用吗?真的会有面试官问这些东西吗? 唉 没办法 选了这条路怎么也得再坚持坚持,不想轻易的放弃 觉得有些可惜,但目前的环境真是逼着你去放弃,继续加油吧 但行好事 莫问前程吧