闭包
和其他大多数现代的语言一样,JavaScript也采用词法作用域(lexical scoping),也就是说,函数的执行依赖于变量的作用域,这个作用域是在函数定义的时候决定的,而不是函数调用时决定的。
为了实现这种词法作用域,JavaScript函数对象的内部状态不仅包含函数的代码逻辑,还必须引用当前作用域链。 –《JavaScript权威指南》
示例
Demo1
|
|
在JavaScript编程,经常有意无意的都会使用闭包,只是通常不知道。
理解闭包一定要记住JavaScript函数对象的内部状态不仅包含函数的代码逻辑,还必须引用当前作用域链
,这句话
Demo2
|
|
Demo3
|
|
在这里闭包体现出了封装性。
Demo4
编程语言中,作用域控制着变量与参数的可见性及生命周期。
大多数类C语言语法的语言都拥有块级作用域。在一个代码块中定义的所有变量在代码块外部是不可见的。定义在代码块中的变量在代码块执行结束后会被释放。这是一件好事。
糟糕的是,尽管JavaScript的代码块貌似支持块级作用域,但实际上并不支持。
JavaScript的函数确实是有函数作用域的。那意味着定义函数中的参数和变量在函数的外部是不可见的,而在一个函数的内部任何位置定义的变量,在函数内部都可见。
–《JavaScript语言精粹》
|
|
通常都会认为结果是 0 1 2 ,但其实并不是而是 3 3 3 。这就是JavaScript没有块级作用域的原因。
上面的例子应该改成
利用函数有作用域的特点,通过立即执行函数创建块级作用域。如果是支持let,将var改成let也是可行的。
闭包引起内存泄露
|
|
下面这段代码会造成内存泄露
为什么?执行这段代码的时候,将匿名函数对象赋值给el的onclick属性;然后匿名函数内部又引用了el对象,存在循环引用,所以不能被回收。
解决方法:
闭包优缺点
优点:
- 可以让一个变量常驻内存
- 避免全局变量的污染
- 私有化变量
缺点:
- 因为闭包会携带包含它的函数的作用域,因此会比其他函数占用更多的内存
- 引起内存泄露