前言
JS基础解析系列, 主要是为了弄清楚JS中一些常见但容易出错,不常见但有助于理解代码的要点。不定时更新,请多多见谅。
闭包是JS中很常见的一种写法。本质是利用函数的嵌套,和函数的作用域(内部函数访问外部变量),来创建出模拟的块级作用域。利用闭包,基本的目的是创造一个封闭的变量,避免污染全局变量,来完成包的封装。
使用示例
闭包常见的使用模式如下:
1 | /** |
以上是简版的防抖函数. 不过也将闭包的一些点展示了出来:
- 内部函数访问外部函数的变量
- 内部函数this的指向问题
- 内存泄漏问题
第一个问题,也是闭包必要性的根本。
假如不使用闭包,要如何实现上面的功能。简洁一点的实现是直接定义一个或者多个全局变量。但定义了全局变量,更多的问题也随之而来。比较棘手的问题有:全局变量污染,内存占用。这些都可能会导致严重的不可预知的bug。使用闭包,最根本上就是为了规避这种难题。通过模拟一个块级作用域,将变量限定在一个范围内,减少对其它代码的影响。
第二个问题,保证this指向一致性。
this的指向也一直是个难题。假如不做处理,this会默认指向当前执行的上下文(context)。以上面的防抖函数为例,为了保持this指向的一致性,就需要一些额外的处理。通过apply传递this, 以及函数的默认参数(arguments), 将当前环境,以及参数传递给需要的执行函数fn,以此来保证this和参数的一致性。在常见的dom操作中,这样就保证了dom和mouseEvent的传递。
第三个问题,内存泄漏
由于闭包导致的内存泄漏,实质上是IE9之前的版本对JScript对象和COM对象使用不同的垃圾回收机制。
1 | // 常见的遍历dom |
除此之外,闭包本身不会因此而造成内存泄漏.
总结
闭包本身的概念是相对简单的,但也是应用极为广泛的存在. 虽然实际应用中会遇到各种变种,但详细掌握后,基本上就不会存在理解的障碍。