写在前面的话Q?br />试图译?http://jibbering.com/faq/faq_notes/closures.html
文中大量提到《ECMA 262 》,我也没时间读q东西,可能有问题理解有误。希望纠正?br />只译了前辚w分,我得理解几天再l下厅R?br />英文水^差,凑合看吧?br />国内找了半天没这文章中文版Q献丑了?br />d有种豁然开朗的感觉Q清楚了很多javascript的问题?br />

一、Introduction
Closure (闭包)
A "closure" is an expression (typically a function) that can have free variables together with an environment that binds those variables (that "closes" the expression).

    闭包是ECMAScript(javascript)语言强大的特征之一Q如果没有真正的理解它的概念Q不可能很好使用它。在一般浏览器环境中,它们很容易被建立Q但也会(x)造成比较隄解的代码逻辑。ؓ(f)了避免闭包引L(fng)~点Q利用它所提供的优点,明白它的机制是重要的。javascript语言的闭包很大程度上依靠 scope chains(函数Q变量的范围? ?javascript对象的灵zȝ属性机?实现?br />    闭包单的解释是,ECMAScript允许inner functions(嵌套函数)Q函数可以定义在另外一个函数里面(关于嵌套函数可以看看<javascript权威指南>Q。这些内部的函数可以讉Kouter functionQ父函数Q的local变量Q参敎ͼ其它内部函数。当内部函数被构造,q可以在函数外被获得Q函数当成返回|Q这个内部函数被?outer functionq回后被执行Q在outer函数外执行)Q那一个闭包Ş成了。(单的理解Qfunction被当成数据类型传递或动态执行)?inner functionq有权利讉K 那些outer functionQ父函数Q的local变量Q参敎ͼ其它内部函数。那些outer functionQ父函数Q的local变量Q参敎ͼ其它内部函数在outer functionq回前就有|q返回的inner function需要改变这些倹{?br />
我估计以下代码就是一个闭包?/p>

 

< script >
var g_count
= 0 ;
function aaa(p)
{ // outer function
 
var outer_count = 0 ;
  function innerfun(name,count)
{ // outer function中定义的另外一个inner function
    return  name + ' : ' + count + ' ? ' ;
  }

 
return  function() { // q回一个匿名的inner函数
     var inner_count = 0 ;
            
return  innerfun( ' g_count ' ,( ++ g_count)) + innerfun( ' outer_count ' ,( ++    outer_count))+innerfun('inner_count',(++inner_count))+p;
  }

}


  var fun1=aaa("fun1");
 var fun2
=aaa("fun2");
 alert(fun1)
 alert(fun1());
//q时候才真正执行
 
alert(fun2());
</script>

    不幸的,完全明白闭包需要知道它背后的机制和一些技术细节?br />二、The Resolution of Property Names on Objects (javascript对象的属?
    ECMAScript认可两类对象Q“Native Object”和“Host Object?Host Object属于Native Object的子c,?ECMA 262 3rd Ed Section 4.3)中叫"Built-in Object"Q内|对象)。Native objects属于语言U别Qhost objects被环境提供(览器等Q,例如Qdocument objects,DOM nodes{?br />    关于对象属性的存取Q数据类型,原型对象prototype的用,我这׃译了?br />    可以参见我的另一文?/a>

三、Identifier Resolution, Execution Contexts and Scope Chains
1、The Execution Context
    执行环境上下文(Execution ContextQ是个抽象的概念Qthe ECMSScript specification (ECMA 262 3rd edition) to define the behaviour required of ECMAScript implementations。规范没有说 execution contexts 应该怎样实现Q但规范中提到execution contexts是个兌属性结构,因此你可以假想ؓ(f)一个有属性的对象Q但不是公有的(publicQ?br />    所有的javascript代码在一个execution context中执行。Global代码(.js文g?在我叫做globla execution context中执行,每个函数的调用有个专属的execution context。注意,用eval函数执行的代码有个独特的execution context.(原文中说eval函数没常被程序员应用Q确实如果掌握闭包用后Q还是可以避免一些eval使用?。在section 10.2 of ECMA 262 (3rd edition)中详l讲q的execution context.
    当一个函数被调用Q那相应的execution context被徏立,如果另外的函敎ͼ或同一个函数递归调用Q,那新的execution context被徏立,直到函数return(对于递归调用Qexecution context是独立的)。因此,javascript代码的执行会(x)建立很多的execution contexts.
    当一个函数的execution context被徏?javascript中有global和function两种Qeval没讨?Q按照顺序,有几个事情要发生?br />   Q?Q?/b>在一个函数的execution context中,一?Activation"对象被徏立(我在
其它文章中叫调用对象Q。the activation被另外规范解释。你可以把它当成一个对象,因ؓ(f)它有对象的属性,但它不是一般对象,它没有原型对象,q不能被javascript代码直接引用?br />   Q?Q?/b>建立一个arguments对象Q它和数l类|以整Cؓ(f)索引来访问|表示函数的参数。它有length和callee属性。这个arguments对象被当成activation对象的属性。在函数内可以直接访问得到?br />   Q?Q?/b>下一步,execution context被分配一?scope属性(scope chain后面讲到Q我们可以把scope理解成对象的一个scope属性,值是scope chainQ。一个scope׃列对象组成(或叫chainQ。每个函数对象也有由chainl成的scope属性。函数的scopeQActivation object+上对象的scope的属?Q这里的scope可以理解成servlet中的chain,一pdhl成的链。)
   Q?Q?/b>Activation object的实例化。Activation object(调用对象)可以看作Variable(变量)?br />function fun(a,b){};fun('p'); a和b?x)当成调用对象的属性,但函数调用是参数不够Qb的gؓ(f)undefined。如果函数内有inner functionQ当成属性赋值给调用对象。变量实例化最后把local variablesQ函数内部声名的变量Q?当成调用对象的参数。调用对象的属?包括函数的参数、内部变量?br />   Q?Q?/b>在函数内Qlocal variables作ؓ(f)调用对象的属性出玎ͼfunction (a){alert(s);   var s='a';}调用Ӟs的值是unidefine,直到执行到赋D句后才有倹{?br />   Q?Q?/b>arguments属性是以烦引标识的参数Q它和显C声明的参数是重复的Qg相同。如果local变量的签名和参数相同Q那么它们三者一个变化,其它都会(x)相应改变倹{见下例
function a(p){alert( arguments [0]);alert(p);var p=1;alert(p);alert( arguments [0]);};a(0);
   Q?Q?/b>最后,为this关键字设|倹{可?new Function()的有些疑问。关于this关键字,感觉自己q没有彻底理解?/font>this关键字关联于执行时的作用域,而非定义时的作用域?The this keyword is relative to the execution context, not the declaration context )

    global execution context 的过E和上面有些不同Q它没有arguments也不需要定义Activation object。global execution context也不需要scope chain,因ؓ(f)scope chain只有一个,是global object.它的变量实例化过E和inner function其实都是根变量和函数,是global对象的属性。global execution context用this应用global对象Q在览器中为window.

2、Scope chains and [[scope]]
    The scope chain of the execution context for a function call is constructed by adding the execution context's Activation/Variable object to the front of the scope chain held in the function object's [[scope]] property。我理解每个函数执行环境都有scope chainQ子函数(inner function)的scope chain包括它的父函数的scope chainQ如此递归对global对象?br />    在ECMAScript中,函数是个对象Q它们可以用function声明Q或function表达式声明,或Function构造函数初始化?br />    用Function构造的函数对象一直有个scope属?指向的scope chain 仅包?global 对象?br />    用function表达式定义的函数对象Q这cd数对象的scope chain被分配到内部的scope 属性?/p>

Q?Q?/b>单的global函数Q例?-
function exampleFunction(formalParameter){
    ...   // function body code
}

在global execution context的变量实例化阶段Qthe corresponding function object 被创建。global execution context有scope chainQ只包含global object.因此Q函数对象被分配一个指向global object?scope属性( internal [[scope]] propertyQ?/p>

Q?Q?/b>A similar scope chain is assigned when a function expression is executed in the global context:-

var exampleFuncRef = function(){
    ...   // function body code
}

q个例子scope chain情Ş与上cM。有个区别是函数对象在代码执行过E才创徏。(?a href="/zkjbeyond/archive/2006/03/30/38191.html">我以前文?/a>Q?br />Q?Q?/b>inner 函数的情形较为复杂,看下面代码:(x)

function exampleOuterFunction(formalParameter){
    function exampleInnerFuncitonDec(){
        ... // inner function body
    }
    ...  // the rest of the outer function body.
}
exampleOuterFunction( 5 );

    outer函数在global execution context变量实例化阶D被创徏Q因此它的scope chain只包括global object.
   当global代码执行到调用exampleOuterFunctionӞ一个新的execution context被创建,(Activation)调用对象也被创徏。这个新的execution context的scope chain׃部分l成Q新的调用对象在层Qouter函数scope chainQ只包括global objectQ在后。新的execution context的变量实例化阶段Qouter 函数体内Q导致inner函数对象被创建,q个inner函数对象的[[scope]] property 被指向上q的哪个scope chain,也就是调用对象和global object.注意inner function也有调用对象?br />

引用?http://wj.cnblogs.com/archive/2006/04/22/381851.html 回复内的代码

<SCRIPT LANGUAGE="JavaScript">
<!--
//global 代码实例化阶D,它知道global object.
function createAClosure()
{
//当调用时Q调用对象创建,execution context的scope chain 包括调用对象和global
//object.
var local = 0;
return function(){return ++local;}; //q个inner function 的scope //chain持有
//createAClosure的调用对象,所以也持有local的?br />}
var c1 = createAClosure(); //调用对象和global object
var c2 = createAClosure(); //另外一个调用对象和global object
document.write(c1() + "<br/>");
document.write(c1() + "<br/>");
document.write(c1() + "<br/>");
document.write(c2() + "<br/>");
document.write(c2() + "<br/>");
//-->
</SCRIPT>

以上所有过E自动进行,代码不需要Q何设|(造成很多Z知道闭包原因Q?br />scope chain 单看来可以按照下面的代码来描qͼ(x)

函数体外Execution context 的scope chain  只有 global.
function fun(){
 函数体内Execution context 的scope chain  fun的调用对?global
    function innerfun(){
      inner函数体内Execution context 的scope chain innerfun的调用对?+ fun的调用对?+ global
    }

}

但是ECMAScript提供的with表达式会(x)修改scope chain.with表达式,我是能不用就不用了,<javascript权威指南>中也说with?x)造成性能的集聚下降。原文脓(chung)在下面。有旉再仔l研I?/p>

The with statement evaluates an expression and if that expression is an object it is added to the scope chain of the current execution context (in front of the Activation/Variable object). The with statement then executes another statement (that may itself be a block statement) and then restores the execution context's scope chain to what it was before.

A function declaration could not be affected by a with statement as they result in the creation of function objects during variable instantiation, but a function expression can be evaluated inside a with statement:-

/* create a global variable - y - that refers to an object:- */
var y = {x:5}; // object literal with an - x - property
function exampleFuncWith(){
    var z;
    /* Add the object referred to by the global variable - y - to the
       front of he scope chain:-
    */
    with(y){
        /* evaluate a function expression to create a function object
           and assign a reference to that function object to the local
           variable - z - :-
        */
        z = function(){
            ... // inner function expression body;
        }
    }
    ...
}

/* execute the - exampleFuncWith - function:- */
exampleFuncWith();
When the exampleFuncWith function is called the resulting execution context has a scope chain consisting of its Activation object followed by the global object. The execution of the with statement adds the object referred to by the global variable y to the front of that scope chain during the evaluation of the function expression. The function object created by the evaluation of the function expression is assigned a [[scope]] property that corresponds with the scope of the execution context in which it is created. A scope chain consisting of object y followed by the Activation object from the execution context of the outer function call, followed by the global object.

When the block statement associated with the with statement terminates the scope of the execution context is restored (the y object is removed), but the function object has been created at that point and its [[scope]] property assigned a reference to a scope chain with the y object at its head.

3、Identifier Resolution
   关于q部分我军_不按照原文直译。Identifier Resolution是一个过E,而不是具体的概念Q我举个例子可能明白了?/p>

<SCRIPT LANGUAGE="JavaScript">
<!--
var s_global='global';//scope chain {global} ?
var s_outer='global';//scope chain {global} ?
var s_inner='global';//scope chain {global} ?
function outerfun(){//scope chain {global} ?
    var s_outer='outer';//scope chain  {outerfun调用对象Qglobal}
 pf('outer代码开?);
 pf(s_global);//global
    pf(s_outer);//outerfun调用对象
    pf(s_inner);//global

 function innerfun(){////scope chain  {outerfun调用对象Qglobal}
    var s_inner='inner';//scope chain  {innerfun调用对象Qouterfun调用对象Qglobal}
 pf('inner代码开?);
 pf(s_global);//global
    pf(s_outer);//outerfun调用对象
    pf(s_inner);//innerfun调用对象
 }
 return innerfun;
}
function pf(msg){document.writeln('</br>'+msg);};
pf('global代码开?);
pf(s_global);//global
pf(s_outer);//global
pf(s_inner);//global

var a=outerfun();
a();
pf('W二个函数开?-----------------------');
var b=outerfun();
b();
//-->
</SCRIPT>

其实Identifier Resolution是属性查扄q程?先从scope chain 的第一个对象开始找Q如果找不到再从scope chain的第二个对象找, global对象始终是scope chain 的最后一个对象,如果global object中也找不到属性,那ؓ(f)undefined.
有两个注意点Q?br />   如果可能Q这个查找过E会(x)对对象的prototypeQ原型对象)查找。先扑֮例属性,再找原型属性。见我的其它文章?br />   在函数内Q这个函数的调用对象包括的参敎ͼlocal变量Qinner函数{?br />
如果有对javascript语言感兴的Q欢q交批评?br />http://www.aygfsteel.com/zkjbeyond/category/10156.html

参考:(x)
    《javascript权威指南?br />     http://jibbering.com/faq/faq_notes/closures.html