JavaScript闭包总结
什么是/如何理解JavaScript中的闭包?
A: 在JavaScript 中,根据词法作用域的规则,内部函数总是可以访问其外部函数中声明的变量,当通过调用一个外部函数返回一个内部函数后,即使该外部函数已经执行结束了,但是内部函数引用外部函数的变量依然保存在内存中。
一个函数和对其周围状态(lexical environment,词法环境)的引用捆绑在一起(或者说函数被引用包围),这样的组合就是闭包(closure)。-- MDN闭包 https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Closures
词法作用域
略。
更改闭包引用的自由变量
JavaScript中,闭包函数是可以改变其引用的外部变量的,这段代码中这里还有一个值得注意的地方是JavaScript中的全局变量,局部变量与变量提升:
1 |
|
如果全局变量跟局部变量重名,局部变量的scope会覆盖掉全局变量的scope。
闭包的回收和内存泄漏:
如果引用闭包的函数是一个全局变量,那么闭包会一直存在直到页面关闭;但如果这个闭包以后不再使用的话,就会造成内存泄漏。所以在使用闭包的时候,你要尽量注意一个原则:如果该闭包会一直使用,那么它可以作为全局变量而存在;但如果使用频率不高,而且占用内存又比较大的话,那就尽量让它成为一个局部变量。
闭包的应用场景
例题:输出结果是什么?
例1
1 |
|
下面这段代码中还应该注意小括号的用法。
关于小括号,如果分号和括号同处上下文,常出现这样的错误,js分号的坑:
1 |
|
例2
1 |
|
语言对比:Python中的闭包
1 |
|
Python的命名空间遵循LEGB顺序, x+=1
会导致Error UnboundLocalError: local variable 'x' referenced before assignment
,使闭包无法更改引用的外部变量,这是由于 +=
操作会导致解释器认为有一个并不存在的局部变量 x
;虽然在python中,闭包强调不可变和纯函数,但从另一个角度,对于 y
来说,由于它是可变对象,有直接在其上操作更改其值的可行性,而 x
是 不可变对象,无法进行任何操作(类比C中的值传递与指针传递),因此,所谓“不写”指的是不改变enclosing变量的内存地址,(python可变对象与不可变对象)函数 inner
有一个只读属性 __closure__
,存储了函数所引用的自由变量 x
,y
。
Useful Links
作用域链和闭包:代码中出现相同的变量,JavaScript引擎如何选择)
变量作用域,闭包
闭包的应用场景,内存泄漏的排查手段等
本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!