闭包
闭包
闭包是什么?
一个函数和对其周围状态的引用捆绑在一起,或者说函数被引用包围,这样的组合就是闭包。闭包让我们可以在一个内层函数中访问到其外层函数的作用域。
「函数」和「函数内部能访问到的变量」(也叫环境)的总和,就是一个闭包。
举例:
1 | |
注意,最后两句和init()();这种调用方法并不相同,后者并没有发挥闭包保存内部变量的作用,这不叫使用了闭包。
举例:
1 | |
闭包的作用是什么?
- 访问块级作用域、封装私有变量、模拟私有方法
举例:
1 | |
当计时器(私有方法)开始执行时,for循环已经结束,每一次的i都是该次所在的块(块级作用域)中的i,所以打印的是当时的i(私有变量)值。
以上代码相当于:
1 | |
此处详细解释见:JS函数的执行时机
- 暴露操作函数而隐藏局部变量
有时,直接使用全局变量很不妥,会出先某些安全问题。我们不能直接访问这些变量,此时就要用到闭包来隐藏局部变量,而仅暴露一个访问器(函数)来间接访问这些变量。
详见:JS 中的闭包是什么?
闭包中的this对象
问题引入:
1 | |
为什么obj.sayColor()();返回的是window.color的值red,而不是obj的blue?
以上代码中,首先创建了一个全局变量color,之后又创建了包含color属性的对象obj。obj对象还包含一个名为sayColor的函数,而这个函数本身又返回的是一个函数color()。
由于函数内部的代码在访问变量时,会沿作用域链查找变量。当函数执行完毕后,局部活动对象会被销毁,内存中就只剩下全局作用域。因此内部函数永远不可能直接访问外部函数的this和arguments变量。
当执行obj.sayColor()后,在函数color()所处的执行上下文中,局部活动对象obj已经被销毁。此时color()只能访问全局作用域中的color变量。
以上代码中,全局变量color和函数color()构成闭包。
要想使obj.sayColor()();返回obj的blue,则应该让obj.color和函数color()构成闭包。
解决方法:
将this保存到闭包可以访问的另一个变量that中:
1 | |
尽管当执行obj.Color()后,其执行上下文的作用域已经被销毁,但函数color()仍然引用了外部函数sayColor的变量(即this),所以他的活动对象obj仍然保存在内存中,进而obj.color仍然可以访问到。
obj是在color()最终执行完毕才被销毁的。
闭包的缺点是什么?
- 因为闭包会保留它们包含函数的作用域,所以比其他函数更占用内存。过度使用闭
包可能导致内存过度占用 。 - 闭包会在父函数外部改变父函数内部变量的值
版权声明:本文作者为「Andy8421」.本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!