还记得刚开始学习JavaScript时,对闭包的抽象描述真的可谓是一看就会,一写就废。主要是不知道实际使用场景是怎样的,经过这些年被各种文章还有代码洗礼之后,发现其实也不过如此。但是在实际开发过程中,一定要考虑使用闭包的场景其实不多,相反地,如果滥用闭包还可能造成更多问题。本着丑化说在前头的原则,我还是先说说该注意的地方,再来看它的用武之地。

性能考虑

内存使用

闭包会保持对其创建时作用域的引用,导致可能的内存泄漏。比如上面这个例子,即使heavyClosure函数执行完毕,largeArray也不会被垃圾回收,因为closure持有对它的引用。这应该算是最常见的一种场景,我在这里构造了一个长度为100000的大数组。

代码可读性和维护性

复杂的闭包使用

上面的代码为每一个元素绑定一个点击事件,但实际上使用了立即执行函数创建了闭包,目的却只是为了保存size变量,显然有点大材小用了,而且很讨厌阅读这样的代码,这里的闭包其实完全是没必要的,我们完全可以这么写。

使用箭头函数及forEach,这样看起来顺眼多了,至少别人读起来也不会有什么心智负担

闭包的作用

丑话说完,当然也该说说它的用武之地了。

1. 数据封装和管理

闭包可以用来封装数据,提供一个方法来访问和修改私有变量,同时保护这些变量不被外部直接访问。下面的计数器示例就确保了count变量只能通过其内部的方法进行操作

创建一个计数器

2. 创建模块化代码

利用闭包,可以创建模块化的代码,使得每个模块都有自己的私有作用域,有助于避免全局命名空间污染和名称冲突。

模块模式

这里,myModule是一个封装良好的模块,其中privateVar对外部是隐藏的,只能通过publicMethod方法间接访问。

3. 函数柯里化和部分应用

刚开始总是记不住函数柯里化是什么,还自己给自己挖了坑,面试官追问什么是函数柯里化,我提了一嘴但是始终组织不起来语言,说得一塌糊涂。后来发现其实结合闭包来理解,这一切就显得非常自然了,说通俗一些,函数柯里化就是将一个接收多个参数的函数,“改造”为一个对外来说只接收一个参数,由其内部实现的方法链式保存参数的函数。

函数柯里化

上面的代码,multiply函数通过闭包返回一个新函数,这个新函数记住了multiply的第一个参数a,使得我们可以创建doubletriple等特定功能的函数。

结论

到此为止,由于业务功能开发的时候,并不需要保证其优秀的模块化和封装能力,所以对于闭包的使用可能还是会偏向保守一些,以后还是要结合优缺点及自身能力来决定如何使用闭包。