什么是闭包?一看就会!

定义

A closure is the combination of a function bundled together (enclosed) with references to its surrounding state (the lexical environment). In other words, a closure gives you access to an outer function’s scope from an inner function. In JavaScript, closures are created every time a function is created, at function creation time.

简单总结:

  1. 一个函数调用时能够访问到外部函数定义的变量或函数时,就会形成闭包。
  2. 闭包的本质是一个对象,存储着函数所用到的外部函数定义的变量或函数。
通过几个例子来帮助理解:
例子一(通过parent函数中调用child函数来创建闭包):
1:   function parent() {
2:     let parentVal = 0;
3:
4:      function child() {
5:        console.log(parentVal);
6:      }
7:      child();
8:   }
9:   parent();
  1. 将断点打在第5行后执行代码。
  2. 代码的执行过程中会创建parent的执行上下文,执行child时,会创建child的执行上下文,child函数可以使用到parent和全局定义的变量。
  3. 由于child函数使用到parent中定义的parentVal,此时child函数执行时就创建了一个Closure,Closure中存放着child使用到外部函数定义的变量。

在这里插入图片描述

  • 小结:
  1. parent函数中调用child函数,且child函数使用到parent中定义的parentVal,由此在child调用时产生闭包。
  2. 由于我们无法直接调用child,只能通过调用parent来调用child,因此每次都会创建一个parent的执行上下文,新的parentVal变量(值为0),调用child时会创建child的执行上下文,此时child访问到的parentVal始终是初始值0。此时闭包对我们来说没有太多的应用价值。
例子二(通过parent函数中返回child函数来创建闭包):
1:    function parent() {
2:      let parentVal = 0;
3:      return function child() {
4:        console.log(parentVal);
5:        parentVal++; // 注意例子二,在child中多加了parentVal++的操作
6:      }
7:    }
8:
9:    const demo = parent();
10:   demo();
11:   demo();
  1. 将断点打在第10、11行后执行代码。
  2. 第9行代码执行后,返回child函数,赋值给demo变量(此时demo是一个具有闭包且功能与child一样的函数)。

在这里插入图片描述

  1. 此时parentVal的值为0,执行第10行代码(即执行demo)后,观察第一次的parentVal的变化。

在这里插入图片描述

  1. 继续执行demo,观察第二次parentVal的变化。

在这里插入图片描述

  • 小结:
  1. 通过parent函数返回child的函数来创建闭包。此时我们会发现在调用parent函数后,demo函数即实现了child的功能又创建了一个闭包。
  2. 这个闭包中存储的是child用到的且属于parent定义的parentVal,是一个有“记忆”功能的状态值(每次执行demo函数对parentVal进行自增操作后,parentVal都会保留执行后的值)。
  3. 为什么闭包中parentVal会具有“记忆”功能呢?因为demo变量赋值parent调用后返回的child函数后,就已经创建好了闭包。且在demo调用时,不再需要创建parent的执行上下文,而是直接从闭包中获取parentVal。

闭包的应用

应用一:防抖节流
    function debounce(fn, delay) {
      let timer = null;
      return function (...args) {
        if (timer) clearTimeout(timer);
        timer = setTimeout(() => {
          fn.apply(this, args);
        }, delay);
      };
    }

    function throttle(fn, delay) {
      let lastTime = 0;
      return function (...args) {
        let curTime = +new Date();
        if (curTime - lastTime > delay) {
          fn.apply(this, args);
          lastTime = curTime;
        }
      };
    }
应用二:错误请求重新发送
    function getData(params, count = 0) {
      return new Promise((resolve, reject) => {
        // api
        getList(params).then(res => {
          resolve(res);
        }).catch(e => {
          count++;
          console.log(`累积请求失败${count}次`);
          if (count >= 2) {
            reject()
          } else {
            getData(params, count);
          }
        })
      })
    }

    function getList() {
      return new Promise((resolve, reject) => {
        setTimeout(() => {
          reject("请求失败");
        }, 1000);
      })
    }

    getData({})
  • 如果存在表述有误或理解偏差的地方,欢迎评论指正~
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值