1 什么是闭包?
在了解闭包之前,我们要先理解JavaScript的作用域。
- 在全局作用域下 声明的变量就是全局变量
- 在局部作用域下 声明的变量就是局部变量
因为作用域链的存在,函数内部可以直接读取全局变量。而函数内部无法读取函数内部的局部变量。
那如果我们如何读取函数内部的变量呢?——闭包。
闭包就是在一个函数内部创建另一个函数,让你可以在一个内层函数中访问到其外层函数的作用域。又或者说,闭包就是能够读取其他函数内部变量的函数。 在本质上,闭包是将函数内部和函数外部连接起来的桥梁。
例子:
在上面的代码中,函数closure2就被包括在函数closure内部,这时closure内部的所有局部变量,对closure2都是可见的。但是反过来就不行,closure2内部的局部变量,对closure就是不可见的。 这就是Javascript语言特有的"链式作用域"结构(chain scope): 子对象会一级一级地向上寻找所有父对象的变量。 所以,父对象的所有变量,对子对象都是可见的,反之则不成立。 既然closure2可以读取closure中的局部变量,那么只要把closure2作为返回值,我们不就可以在closure外部读取它的内部变量了吗
2 为什么用闭包
了解过闭包后,我们都会考虑到为什么用闭包 怎么用闭包,下面我们就谈谈为什么用闭包?
首先我们要知道闭包具有
(1) 高继承和封装性; (2) 避免全局变量污染。的优点和缺点。
1)优点
可以从内部函数访问外部函数的作用域中的变量,且访问到的变量长期驻扎在内存中,可供之后使用 避免变量污染全局
把变量存到独立的作用域,作为私有成员存在
2)缺点
对内存消耗有负面影响。因内部函数保存了对外部变量的引用,导致无法被垃圾回收,增大内存使用量,所 以使用不当会导致内存泄漏
对处理速度具有负面影响。闭包的层级决定了引用的外部变量在查找时经过的作用域链长度可能获取到意外的值(captured value)
3)应用场景 闭包的应用场景非常多,只要用到了函数柯里化的地方就有闭包的身影,比如防抖节流、定时器、惰性处理等
例子1: 应用场景一: 典型应用是模块封装,在各模块规范出现之前,都是用这样的方式防止变量污染全局。
例子2: 应用场景二: 在循环中创建闭包,防止取到意外的值。 如下代码,无论哪个元素触发事件,都会弹出 3。因为函数执行后引用的 i 是同一个,而 i 在循环结束后就是 3
3 怎么用闭包
代码中经常会用到闭包,下面举一个例子
例子:
如上,调用接口1中的参数data 和调用接口2中的data 两个对象同名,但是互相不影响参数,定义在函数内部的变量外界访问不到,每个data在各个函数作用域内部,只能在函数内部访问。
使用闭包的注意点:
(1)由于闭包会使得函数中的变量都被保存在内存中,内存消耗很大,所以不能滥用闭包,否则会造成网页的性能问题,在IE中可能导致内存泄露。解决方法是,在退出函数之前,将不使用的局部变量全部删除。
(2)闭包会在父函数外部,改变父函数内部变量的值。所以,如果你把父函数当作对象(object)使用,把闭包当作它的公用方法(Public Method),把内部变量当作它的私有属性(private value),这时一定要小心,不要随便改变父函数内部变量的值。
——————————————————————————————————————
每日分享: 感悟精彩人生,体验不同色彩! 《陈行甲人生笔记》