Javascript 闭包
Javascript闭包
说到javascript的闭包,就要先说一下传统语言的一些特征,如C,Java,C#等等,void Test() {int i = 0;}
,当Test方法调用结束时,执行栈弹出,局部变量被回收,而js的闭包,则是提供了一种在test这个执行域(函数)消亡时,仍能够访问i的方式。
1 2 3 4 5 6 |
|
1.闭包原理
闭包的原理涉及到ECMAScript语言的一些特征,下面进行详述
1.1 Execution Context
控制权转移到一段可执行代码时候,就会产生一个Execution Context(简称EC)。
一段可执行代码在ECMAScript里的定义可视为一个function(eval暂不提,strict mode也将其排除在外),即函数调用的时候,就会通过压栈的方式将一个个function的ECStack压入栈中,该function return的时候就从栈中pop出来,用个简单的例子来形容:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
|
而每个context又是由什么组成的呢,
context = {
VO = {}, //variable object,函数调用时的内部变量的集合,包括arguments,内部方法等.
this , //不赘述了,简而言之就是caller(
a.b()的a),当然new是另一情况了
scope chain = [] //见下文,用于变量查找
}
附上 VO,
this,
闭包的产生主要是Scope Chain原因,但是强烈推荐以上几篇文章,对于理解ECMAScript的机制有很大帮助,能让人顿悟很多东西。
1.2 Scope
Scope上下文,即是在执行语句时候能够访问到的所有变量的集合,Javascript是允许inner function存在的,因而其Scope就是一个链表形式的存在,其最顶端就是window(浏览器环境),然后每定义一个function,就定义一个Scope Object,保存一个outer reference,以访问上一级变量集合,形成一个层级式的链,处于最底部的function会一层一层向上找变量,这也是为什么不要使用
t = 'without var is global var'
,会大大降低执行效率。附上ECMA-262
而每个Scope保存的out reference是由function定义时决定的,而不是调用执行时决定的,如
1 2 3 4 5 6 7 8 9 10 |
|
alert结果是5而非4,如果把最上级的right定义注释掉,则right is not defined。所以这个时候是不是能理解闭包的原理了,虽然greeting方法已经消亡,但是返回的匿名函数的Scope保存有其上一级的outer reference,也就是text变量等的集合。
下一篇文章会介绍一下使用闭包的场景和相应的危害,欢迎拍砖。