更多技术分享,请点击右上角红色的“关注”。谢谢你的支持!闭包的基本概念闭包不仅限于JavaScript,还用于许多语言,如PHP、Scala、Groovy、Ruby、Python、swift和Java(Java8及更高版本)。

简单来说,闭包就是能够读取其他函数内部变量的函数。例如在javascript中,只有函数内部的子函数才能读取局部变量,所以闭包可以理解成“定义在一个函数内部的函数“。

在本质上,闭包是将函数内部和函数外部连接起来的桥梁。

只看这些概念,是不是有点蒙圈了,别急,且往下看。


结合代码来说明

如果一个函数a定义在另一个函数b里面,那么,这个函数a就是一个闭包。

重要的关键点,函数a能够直接读取函数b中定义的变量,这个就是闭包的特性

再来一段有意思的代码例子:

函数b这次不再直接执行a了,而是直接返回了函数a,所以func本质上是对函数a实例的引用,

而func()竟然能记住x,这就是JavaScript的闭包机制的神奇之处。

到这里,我们结合以上代码说明,闭包就是函数a和变量x。


闭包可以用来做什么

工作中,不知不觉,我们其实经常用到闭包,比如下面这个例子,一个初始化函数里面包含一个按钮点击事件:

另一个具体点的例子,一段发送验证码的Demo:

可以看到,在onclick函数里面,是可以正常操作time_wait和time_left变量的,细心的朋友可能已经发现,

代理里边已经出现两个闭包的应用了,一处是onclick,还有一处就是setInterval这个定时函数。

我们再想想,为什么要用闭包?什么场景需要呢?

  • JavaScript语言特性需要(setTimeout、setInterval…)

  • 事件绑定需要(onclick…)

还有一个重要的原因,那就是OO思想,把上面发送验证码的代码改造一下来看看

这样,已经变成面向对象的编程风格了。


什么时候不该用闭包

注意了朋友,不要为了秀技巧,到处使用闭包。因为滥用闭包可能会导致脚本执行缓慢,以及消耗不必要的内存。尤其是以下两种情况时,应该尽量避免。

1.循环

页面上测试,你会发现无论你点击哪个按钮,都会弹出4,因为click函数是个闭包,页面加载后循环开始执行,当你点击按钮的时候,循环已经执行完了,此时i值为4,而闭包记得它周围的变量,所以弹出的都是4。

要解决这个问题,可以把打印的代码提炼到另一个函数里面,这样就会产生一个新的作用域:

或者用立即执行函数表达式:

2.构造器

方法应该关联于对象的原型,而不要定义到对象的构造器中。原因是这将导致每次对象实例化时,方法都会被重新定义一次。

应该这样改写,让继承的原型可以为所有实例共享:


结论

闭包就是一个函数引用另外一个函数的变量,因为变量被引用着所以不会被回收,因此可以用来封装一个私有变量。这是优点也是缺点,不必要的闭包只会徒增内存消耗!另外使用闭包也要注意变量的值是否符合你的要求,因为他就像一个静态私有变量一样。闭包通常会跟很多东西混搭起来,接触多了才能加深理解,这里只是开个头说说基础性的东西。

相关推荐