用 [[scope]] 解释闭包 JavaScript 闭包

什么是闭包

MDN 中的解释:一个函数和对其周围状态(词法环境)的引用捆绑在一起(或者说函数被引用包围),这样的组合就是闭包(closure)。也就是说,闭包让你可以在一个内层函数中访问到其外层的作用域。在 JavaScript 中,每当创建一个函数,闭包就会在函数创建的同时被创建出来。

第一句可以理解为:

  1. 闭包就是函数与声明该函数的词法环境(本文主指[[ scope ]]属性)的组合。
  2. 闭包就是带着词法环境的函数
  3. 闭包就是一个有 [[ scope ]] 的函数

[[ scope ]]

函数创建时会创建函数的作用域链,保存到函数对象的[[ scope ]]属性中,作用域链其实就是一个数组,里面按顺序、按需要保存着上级执行环境中变量对象的数据(不一定是完整的变量对象,函数中没有用到的将不会保存,即按需要)

let add;
{
    let a = 10 //函数中没有用到a变量,不会报错到函数的作用域链中,即按需要
    let count = 0
    add = () => {
        console.log(count++)
    }
}

在这里插入图片描述

函数作用域([[ scope ]])的形成

是在函数定义的地方,向上级作用域延申, 不是在执行的地方。

带词法环境的函数

let add;
{
    let count = 0
    add = () => {
        console.log(count++)
    }
}
console.dir(add)//同时也解释了开篇闭包定义中最后一句话,闭包在函数创建的时候就存在了,而不是调用时

在这里插入图片描述
不带词法环境的函数
在这里插入图片描述
所有Javascript函数都是闭包吗

如果根据MDN的定义来判断的话,浏览器自定义api函数都是内部实现没有词法环境,不是闭包,但是开发者自定义的函数基本上都是,即便全局定义一个函数它也有 [[ scope ]] ,它也可以访问全局执行环境中的变量对象。

es6的箭头函数也是闭包,它是函数与词法环境this的组合

为什么闭包中的变量可以重用

let add;
{
    let count = 0
    add = () => {
        console.log(count++)
    }
}

上述示例中:把一个函数作为值给了全局变量add,变量add不解除对函数的引用就一直持有对函数的引用,函数的作用域链也一直保存着,所以可以重用,销毁闭包的关键就是解除add对函数的引用

闭包内存泄漏

闭包会把上级执行环境中的变量对象保存在自己的作用域链中了,会比一般的函数占用更多内存。

如果可以用对象存状态就尽量不要用闭包

为什么?

  • 闭包会内存泄漏,用对象实现不会
  • 闭包不是纯函数,它有状态,但是不透明只能通过console查看不方便调试,容易滋生bug。用对象可以debugger、拷贝状态、回溯状态,容易调试
  • 现在主流的状态管理框架Flux、Redux、Vuex的思想全都是集中状态管理。还把状态分散到一个一个闭包里面,是过时的
//用对象实现防抖
class debounce{
  constructor(){
    this.timer = null
  }
  run(callback,delay){
    clearTimeout(this.timer)
    this.timer = setTimeout(() => {
      callback()
    }, delay);
  }
}
let d = new debounce()
let callBack = () => console.log(111)
d.run(callBack,2000) 
d.run(callBack,2000) //两秒后打印 111
//用函数实现防抖
let debounce = () => {
  let timer = null
  return (callback,delay) => {
    clearTimeout(timer)
    timer = setTimeout(() => {
      callback()
    }, delay);
  }
}
let d = debounce()
let callBack = () => console.log(111)
d(callBack,2000) 
d(callBack,2000) //两秒后打印 111
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值