关于无处不在的闭包

闭包是函数和函数的词法环境的引用的组合 [MDN]
闭包是指有权访问另外一个函数做用域中的变量的函数 [JS高级程序设计]
闭包是内部函数引用外部函数的变量的集合 [李兵]
闭包是一个绑定了执行环境的函数 [程劭非]

1. 什么是闭包

欲懂闭包,必先知道做用域、做用域链的含义。那么咱们就从做用域开始讲起。html

(1)做用域 = 去哪里找变量

函数执行时会造成调用栈,调用函数时其执行上下文(其中保存了:变量环境和词法环境)入栈,执行完毕出栈。执行上下文存储着函数中声明的变量,函数执行也会访问其余函数中声明的变量。在函数执行查找变量时,变量的可见范围就是做用域,查找变量的链路就变量的做用域链
查找变量时遵循两个规则:第1,函数嵌套时内部函数总能访问外部函数中声明的变量;第2,调用栈中的函数,老是先在自身的执行上下文找变量,再到最外层的全局执行上下文去找数组

(2)闭包 = 函数 + 变量

定义: 持有着其它做用域中变量的函数 及其持有的其它变量的集合 的组合
  • 闭包产生的过程:闭包一般产生于函数嵌套时。外部outer函数声明了变量o,内部函数inner能够访问到o。当inner函数被做为返回值被outer返回, outer函数执行完毕以后,outer的执行上下文就弹出了调用栈。此时变量o应该被GC回收掉,但因为inner函数此时还引用时变量o, o并无随着outer的执行完毕而销毁,此时咱们称产生了闭包。
  • 闭包产生的缘由:即便外部函数已经执行完,因为内部函数持有外部函数中变量的引用,外部函数做用域的变量依然存在在内存之中
产生闭包以后,变量的查找链路就会发生变化。首先在自身的执行上下文找变量,再到闭包中去找,最后再到最外层的全局执行上下文去找

2. 闭包的特征

(1)函数的返回值是函数
(2)函数做为参数传递给另外的函数闭包

回调函数都是闭包,由于函数被当作参数传递了

3. 闭包的使用场景

根据上述第2点,闭包的特征仍是比较明显的。本节介绍闭包的具体应用场景。
(1)全部使用到回调函数的地方都是闭包的应用,如事件监听回调、Promise绑定的then回调、数组的map()函数;
(2)利用闭包模仿块级做用域、封装私有变量、延长局部变量的寿命;
(3)闭包和setTimeOut()结合实现防抖、节流;
(4)函数柯里化:多参数函数转化成单参函数,好处是能够进行参数复用。函数

// 普通的add函数
function add(x, y) {
    return x + y
}
// Currying后
function curryingAdd(x) {
    return function (y) {
        return x + y
    }
}
add(1, 2)           // 普通函数调用3
curryingAdd(1)(2)   // 柯里化函数调用3

4. 注意事项

闭包会携带包含其它函数的做用域,所以会比其余函数占用更多的内存,容易致使内存泄漏。若是闭包会一直使用,那么它能够做为全局变量而存在;但若是使用频率不高,并且占用内存又比较大的话,那就尽可能让它成为一个局部变量。post

总结

本文以变量的查找做为出发点,引出了变量做用域、做用域链、函数的调用栈等概念。而后介绍了闭包的组成、造成过程。闭包听起来玄妙,用起来简单。文中还总结了闭包的典型特征,有助于咱们在实际的开发过程当中发现闭包、理解闭包。最后,还介绍了闭包的具体使用场景,也给出了其缺点、使用注意事项。设计

参考:
https://juejin.cn/post/694469...
https://www.cnblogs.com/gg-qq...
https://time.geekbang.org/col...code

相关文章
相关标签/搜索