聊聊闭包

152 阅读2分钟

不使用闭包的防抖

    window.onresize =  () => {
      debounce(fn, 1000)
    }
    function fn () {
      console.log('fn')
    }
    let time = ''
    function debounce(fn, timeLong) {
      if (time) {
        clearTimeout(time)
        time = ''
      }
      time = setTimeout(() => {
        fn()
      }, timeLong)
    }

使用闭包的防抖

    window.onresize = debounce(fn, 1000)
    function fn() {
      console.log('fn')
    }
    function debounce(fn, timeLong) {
      let timer = ''
      return function () {
        if (timer) {
          clearTimeout(timer)
          timer = ''
        }
        timer = setTimeout(function () {
          fn()
        }, timeLong)
      }
    }
  • 不使用闭包来防抖,会创建一个全局变量 time,造成变量污染

  • 使用闭包来防抖,引用的是函数内的局部私有变量time

  • 不使用闭包还需要单独外包一个函数来形成事件监听句柄

闭包产生的原因

函数中的局部变量在函数执行完后会被销毁,有时候,我们不希望这个局部变量会被销毁,我们还想在外部进行持续的操作和访问,我们就会用到闭包这种方式。

为什么不创建一个全局变量来代替这个局部变量?

因为全局变量会被污染或者被修改。

闭包能够访问里面的变量,是由于作用域链,用到了函数嵌套中,内部函数能够访问父级函数作用域的变量这个理念。

使用场景

  • 项目很多的封装都是基于闭包。模块化是闭包最好的场景;
  • 防抖节流
  • 柯理化函数

闭包解释,极简易懂:

闭包没有那么复杂,本质就是上级作用域内变量的生命周期,因为被下级作用域内引用,而没有被释放。就导致上级作用域内的变量,等到下级作用域执行完以后才正常得到释放。

结合作用域生命周期解释闭包:

在js执行环境,你的全局作用域(window)是最大的作用域,你可以定义很多块级作用域。因为销毁全局作用域是你整个页面停止和关闭;所以每个函数内部都可以看作一个作用域,当函数内部返回一个函数且子函数没在父级作用域内完成整个生命周期的话,父级函数是没办法完成一整个生命周期的,闭包正是利用这一点卡住了父级函数的作用域, 如果你在父级函数中子函数执行完成返回一个基本类型的话是没办法卡住父级作用域的生命周期的。面试的时候,提到闭包,没必要去纠结,直接回答函数嵌套函数,且内部函数调用父级作用域的变量就可以称之为闭包了。