JavaScript之闭包(closure)
“JavaScript中的函数运行在它们被定义的作用域里,而不是它们被执行的作用域里。”
一些关于闭包的定义:
- 闭包是指有权访问另一个函数作用域中变量的函数 --《JS高级程序设计第三版》 p178
- 函数对象可以通过作用域链相关联起来,函数体内部的变量都可以保存在函数作用域内,这种特性称为 ‘闭包’ 。 --《JS权威指南》 p183
- 内部函数可以访问定义它们的外部函数的参数和变量(除了
this
和arguments
)。 --《JS语言精粹》 p36
要理解js中的闭包必须清楚另一个概念scope。JS中采用”链式作用域”结构(chain scope),子对象可以一级一级地向上寻找所有父对象的变量。
JS的scope基于function,而function是可以作为普通对象到处传递的,经常会有一个function内部定义的函数放到其他地方使用的情况。所谓的闭包就是当函数在其他地方使用的时候能保存下函数所需要的运行环境,也即是函数能保存下函数诞生时的环境。
var a=1 var b=function(){ return a+1 } b() // => 2
这个案例中,变量a是一个依赖闭包机制所捕获的自由变量,也因此函数b可以被正常执行。(作者:项昊凡 链接:https://www.zhihu.com/question/34547104/answer/59560912)
另一种说法:
代码指令执行时候,会处于一定的环境,单纯将代码保存下来,还是不够的,需要将代码所处的环境也保存下来。闭包其实是,将代码跟代码所处于的环境做为一个整体来看待。周围的环境,表现为代码所使用的数据。在有些语言中,这个概念叫代码块(block),匿名函数(lambda)等等。
数据跟代码不再人为割裂开来,统一起来看待。闭包就会是很自然的概念。数据可以传递,从一个地方传递到另一个地方,并且以后再使用。闭包从某个角度来说,也是数据,当然也可以传递,从一个函数传递到另一个函数,也可以保持下来,以后再调用。因为将环境也保持下来了,以后调用的时候,就还原当时的情况,延迟执行,就很容易,很自然地实现了。而延迟执行有什么作用?就是另一个话题了。(作者:黄兢成 链接:https://www.zhihu.com/question/24084277/answer/28476841)
再一个Javascript闭包的例子:
function A(x){ return function B(y) { return x*y } }
首先,变量x对于B(y)来说是一个外部自由变量,B()调用时需要x;其次,B的外部环境A包含x;再次,JS允许B访问A的变量。
转一道有意思的题目:
function fun(n,o) { console.log(o) return { fun:function(m){ return fun(m,n); } }; } var a = fun(0); a.fun(1); a.fun(2); a.fun(3);//undefined,?,?,? var b = fun(0).fun(1).fun(2).fun(3);//undefined,?,?,? var c = fun(0).fun(1); c.fun(2); c.fun(3);//undefined,?,?,? //问:三行a,b,c的输出分别是什么?
答案请查阅原文:http://www.jb51.net/article/75450.htm