国产一级a片免费看高清,亚洲熟女中文字幕在线视频,黄三级高清在线播放,免费黄色视频在线看

打開(kāi)APP
userphoto
未登錄

開(kāi)通VIP,暢享免費(fèi)電子書(shū)等14項(xiàng)超值服

開(kāi)通VIP
javascript語(yǔ)言中的閉包

試圖翻譯自 http://jibbering.com/faq/faq_notes/closures.html
文中大量提到《ECMA 262 》,我也沒(méi)時(shí)間讀這東西,可能有問(wèn)題理解有誤。希望糾正。
只譯了前邊部分,我得理解幾天再繼續(xù)下去。
英文水平差,湊合看吧。
國(guó)內(nèi)找了半天沒(méi)這篇文章中文版,獻(xiàn)丑了就。
讀后有種豁然開(kāi)朗的感覺(jué),清楚了很多javascript的問(wèn)題。

一、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)語(yǔ)言強(qiáng)大的特征之一,如果沒(méi)有真正的理解它的概念,不可能很好使用它。在一般瀏覽器環(huán)境中,它們很容易被建立,但也會(huì)造成比較難理解的代碼邏輯。為了避免閉包引起的缺點(diǎn),利用它所提供的優(yōu)點(diǎn),明白它的機(jī)制是重要的。javascript語(yǔ)言的閉包很大程度上依靠 scope chains(函數(shù),變量的范圍鏈) 和 javascript對(duì)象的靈活的屬性機(jī)制 實(shí)現(xiàn)。
    閉包簡(jiǎn)單的解釋是,ECMAScript允許inner functions(嵌套函數(shù)):函數(shù)可以定義在另外一個(gè)函數(shù)里面(關(guān)于嵌套函數(shù)可以看看<javascript權(quán)威指南>)。這些內(nèi)部的函數(shù)可以訪問(wèn)outer function(父函數(shù))的local變量,參數(shù),其它內(nèi)部函數(shù)。當(dāng)內(nèi)部函數(shù)被構(gòu)造,并可以在函數(shù)外被獲得(函數(shù)當(dāng)成返回值),這個(gè)內(nèi)部函數(shù)被在 outer function返回后被執(zhí)行(在outer函數(shù)外執(zhí)行),那一個(gè)閉包形成了。(簡(jiǎn)單的理解,function被當(dāng)成數(shù)據(jù)類型傳遞或動(dòng)態(tài)執(zhí)行)。 inner function還有權(quán)利訪問(wèn) 那些outer function(父函數(shù))的local變量,參數(shù),其它內(nèi)部函數(shù)。那些outer function(父函數(shù))的local變量,參數(shù),其它內(nèi)部函數(shù)在outer function返回前就有值,并返回的inner function需要改變這些值。

我估計(jì)以下代碼就是一個(gè)閉包。

 

< script >
var g_count
= 0 ;
function aaa(p)
{ // outer function
 
var outer_count = 0 ;
  function innerfun(name,count)
{ // outer function中定義的另外一個(gè)inner function
    return  name + : + count + 次; ;
  }

 
return  function() { // 返回一個(gè)匿名的inner函數(shù)
     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());
//這時(shí)候才真正執(zhí)行
 
alert(fun2());
</script>

    不幸的,完全明白閉包需要知道它背后的機(jī)制和一些技術(shù)細(xì)節(jié)。
二、The Resolution of Property Names on Objects (javascript對(duì)象的屬性)
    ECMAScript認(rèn)可兩類對(duì)象,“Native Object”和“Host Object”,Host Object屬于Native Object的子類,在(ECMA 262 3rd Ed Section 4.3)中叫"Built-in Object"(內(nèi)置對(duì)象)。Native objects屬于語(yǔ)言級(jí)別,host objects被環(huán)境提供(瀏覽器等),例如,document objects,DOM nodes等。
    關(guān)于對(duì)象屬性的存取,數(shù)據(jù)類型,原型對(duì)象prototype的使用,我這就不譯了。
    可以參見(jiàn)我的另一篇文章

三、Identifier Resolution, Execution Contexts and Scope Chains
1、The Execution Context
    執(zhí)行環(huán)境上下文(Execution Context)是個(gè)抽象的概念,the ECMSScript specification (ECMA 262 3rd edition) to define the behaviour required of ECMAScript implementations。規(guī)范沒(méi)有說(shuō) execution contexts 應(yīng)該怎樣實(shí)現(xiàn),但規(guī)范中提到execution contexts是個(gè)關(guān)聯(lián)屬性結(jié)構(gòu),因此你可以假想為一個(gè)有屬性的對(duì)象,但不是公有的(public)。
    所有的javascript代碼在一個(gè)execution context中執(zhí)行。Global代碼(.js文件中)在我叫做globla execution context中執(zhí)行,每個(gè)函數(shù)的調(diào)用有個(gè)專屬的execution context。注意,用eval函數(shù)執(zhí)行的代碼有個(gè)獨(dú)特的execution context.(原文中說(shuō)eval函數(shù)沒(méi)常被程序員應(yīng)用,確實(shí)如果掌握閉包使用后,還是可以避免一些eval使用的)。在section 10.2 of ECMA 262 (3rd edition)中詳細(xì)講述的execution context.
    當(dāng)一個(gè)函數(shù)被調(diào)用,那相應(yīng)的execution context被建立,如果另外的函數(shù)(或同一個(gè)函數(shù)遞歸調(diào)用),那新的execution context被建立,直到函數(shù)return(對(duì)于遞歸調(diào)用,execution context是獨(dú)立的)。因此,javascript代碼的執(zhí)行會(huì)建立很多的execution contexts.
    當(dāng)一個(gè)函數(shù)的execution context被建立(javascript中有g(shù)lobal和function兩種,eval沒(méi)討論),按照順序,有幾個(gè)事情要發(fā)生。
   (1)在一個(gè)函數(shù)的execution context中,一個(gè)"Activation"對(duì)象被建立(我在其它文章中叫調(diào)用對(duì)象)。the activation被另外規(guī)范解釋。你可以把它當(dāng)成一個(gè)對(duì)象,因?yàn)樗袑?duì)象的屬性,但它不是一般對(duì)象,它沒(méi)有原型對(duì)象,并不能被javascript代碼直接引用。
   (2)建立一個(gè)arguments對(duì)象,它和數(shù)組類似,以整數(shù)為索引來(lái)訪問(wèn)值,表示函數(shù)的參數(shù)。它有l(wèi)ength和callee屬性。這個(gè)arguments對(duì)象被當(dāng)成activation對(duì)象的屬性。在函數(shù)內(nèi)可以直接訪問(wèn)得到。
   (3)下一步,execution context被分配一個(gè) scope屬性(scope chain后面講到,我們可以把scope理解成對(duì)象的一個(gè)scope屬性,值是scope chain)。一個(gè)scope由一列對(duì)象組成(或叫chain)。每個(gè)函數(shù)對(duì)象也有由chain組成的scope屬性。函數(shù)的scope=Activation object+上級(jí)對(duì)象的scope的屬性.(這里的scope可以理解成servlet中的chain,一系列請(qǐng)求組成的鏈。)
   (4)Activation object的實(shí)例化。Activation object(調(diào)用對(duì)象)可以看作Variable(變量)。
function fun(a,b){};fun(‘p‘); a和b會(huì)當(dāng)成調(diào)用對(duì)象的屬性,但函數(shù)調(diào)用是參數(shù)不夠,b的值為undefined。如果函數(shù)內(nèi)有inner function,當(dāng)成屬性賦值給調(diào)用對(duì)象。變量實(shí)例化最后把local variables(函數(shù)內(nèi)部聲名的變量) 當(dāng)成調(diào)用對(duì)象的參數(shù)。調(diào)用對(duì)象的屬性 包括函數(shù)的參數(shù)、內(nèi)部變量。
   (5)在函數(shù)內(nèi),local variables作為調(diào)用對(duì)象的屬性出現(xiàn),function (a){alert(s);   var s=‘a(chǎn)‘;}調(diào)用時(shí),s的值是unidefine,直到執(zhí)行到賦值語(yǔ)句后才有值。
   (6)arguments屬性是以索引標(biāo)識(shí)的參數(shù),它和顯示聲明的參數(shù)是重復(fù)的,值也相同。如果local變量的簽名和參數(shù)相同,那么它們?nèi)咭粋€(gè)變化,其它都會(huì)相應(yīng)改變值。見(jiàn)下例
function a(p){alert( arguments [0]);alert(p);var p=1;alert(p);alert( arguments [0]);};a(0);
   (7)最后,為this關(guān)鍵字設(shè)置值。可能 new Function()的有些疑問(wèn)。關(guān)于this關(guān)鍵字,感覺(jué)自己還沒(méi)有徹底理解。this關(guān)鍵字關(guān)聯(lián)于執(zhí)行時(shí)的作用域,而非定義時(shí)的作用域。(The this keyword is relative to the execution context, not the declaration context )

    global execution context 的過(guò)程和上面有些不同,它沒(méi)有arguments也不需要定義Activation object。global execution context也不需要scope chain,因?yàn)閟cope chain只有一個(gè),就是global object.它的變量實(shí)例化過(guò)程和inner function其實(shí)都是根變量和函數(shù),就是global對(duì)象的屬性。global execution context用this應(yīng)用global對(duì)象,在瀏覽器中為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。我理解每個(gè)函數(shù)執(zhí)行環(huán)境都有scope chain,子函數(shù)(inner function)的scope chain包括它的父函數(shù)的scope chain,如此遞歸對(duì)global對(duì)象。
    在ECMAScript中,函數(shù)是個(gè)對(duì)象,它們可以用function聲明,或function表達(dá)式聲明,或Function構(gòu)造函數(shù)初始化。
    用Function構(gòu)造的函數(shù)對(duì)象一直有個(gè)scope屬性,指向的scope chain 僅包括 global 對(duì)象。
    用function表達(dá)式定義的函數(shù)對(duì)象,這類函數(shù)對(duì)象的scope chain被分配到內(nèi)部的scope 屬性。

(1)簡(jiǎn)單的global函數(shù),例如:-
function exampleFunction(formalParameter){
    ...   // function body code
}

在global execution context的變量實(shí)例化階段,the corresponding function object 被創(chuàng)建。global execution context有scope chain,只包含global object.因此,函數(shù)對(duì)象被分配一個(gè)指向global object的 scope屬性( internal [[scope]] property)。

(2)A similar scope chain is assigned when a function expression is executed in the global context:-

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

這個(gè)例子scope chain情形與上類似。有個(gè)區(qū)別是函數(shù)對(duì)象在代碼執(zhí)行過(guò)程才創(chuàng)建。(見(jiàn)我以前文章
(3)inner 函數(shù)的情形較為復(fù)雜,看下面代碼:

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

    outer函數(shù)在global execution context變量實(shí)例化階段被創(chuàng)建,因此它的scope chain只包括global object.
   當(dāng)global代碼執(zhí)行到調(diào)用exampleOuterFunction時(shí),一個(gè)新的execution context被創(chuàng)建,(Activation)調(diào)用對(duì)象也被創(chuàng)建。這個(gè)新的execution context的scope chain由兩部分組成,新的調(diào)用對(duì)象在頂層,outer函數(shù)scope chain(只包括global object)在后。新的execution context的變量實(shí)例化階段(outer 函數(shù)體內(nèi))導(dǎo)致inner函數(shù)對(duì)象被創(chuàng)建,這個(gè)inner函數(shù)對(duì)象的[[scope]] property 被指向上述的哪個(gè)scope chain,也就是調(diào)用對(duì)象和global object.注意inner function也有調(diào)用對(duì)象。

引用了 http://wj.cnblogs.com/archive/2006/04/22/381851.html 回復(fù)內(nèi)的代碼

<SCRIPT LANGUAGE="JavaScript">
<!--
//global 代碼實(shí)例化階段,它知道global object.
function createAClosure()
{
//當(dāng)調(diào)用時(shí),調(diào)用對(duì)象創(chuàng)建,execution context的scope chain 包括調(diào)用對(duì)象和global
//object.
var local = 0;
return function(){return ++local;}; //這個(gè)inner function 的scope //chain持有
//createAClosure的調(diào)用對(duì)象,所以也持有l(wèi)ocal的值
}
var c1 = createAClosure(); //調(diào)用對(duì)象和global object
var c2 = createAClosure(); //另外一個(gè)調(diào)用對(duì)象和global object
document.write(c1() + "<br/>");
document.write(c1() + "<br/>");
document.write(c1() + "<br/>");
document.write(c2() + "<br/>");
document.write(c2() + "<br/>");
//-->
</SCRIPT>

以上所有過(guò)程自動(dòng)進(jìn)行,代碼不需要任何設(shè)置(造成很多人不知道閉包原因)。
scope chain 簡(jiǎn)單看來(lái)可以按照下面的代碼來(lái)描述:

函數(shù)體外Execution context 的scope chain  只有 global.
function fun(){
 函數(shù)體內(nèi)Execution context 的scope chain  fun的調(diào)用對(duì)象+global
    function innerfun(){
      inner函數(shù)體內(nèi)Execution context 的scope chain innerfun的調(diào)用對(duì)象 + fun的調(diào)用對(duì)象 + global
    }

}

但是ECMAScript提供的with表達(dá)式會(huì)修改scope chain.with表達(dá)式,我是能不用就不用了,<javascript權(quán)威指南>中也說(shuō)with會(huì)造成性能的集聚下降。原文貼在下面。有時(shí)間再仔細(xì)研究。

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
   關(guān)于這部分我決定不按照原文直譯。Identifier Resolution是一個(gè)過(guò)程,而不是具體的概念,我舉個(gè)例子可能就明白了。

<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調(diào)用對(duì)象,global}
 pf(‘outer代碼開(kāi)始‘);
 pf(s_global);//global
    pf(s_outer);//outerfun調(diào)用對(duì)象
    pf(s_inner);//global

 function innerfun(){////scope chain  {outerfun調(diào)用對(duì)象,global}
    var s_inner=‘inner‘;//scope chain  {innerfun調(diào)用對(duì)象,outerfun調(diào)用對(duì)象,global}
 pf(‘inner代碼開(kāi)始‘);
 pf(s_global);//global
    pf(s_outer);//outerfun調(diào)用對(duì)象
    pf(s_inner);//innerfun調(diào)用對(duì)象
 }
 return innerfun;
}
function pf(msg){document.writeln(‘</br>‘+msg);};
pf(‘global代碼開(kāi)始‘);
pf(s_global);//global
pf(s_outer);//global
pf(s_inner);//global

var a=outerfun();
a();
pf(‘第二個(gè)函數(shù)開(kāi)始------------------------‘);
var b=outerfun();
b();
//-->
</SCRIPT>

其實(shí)Identifier Resolution就是屬性查找的過(guò)程。 先從scope chain 的第一個(gè)對(duì)象開(kāi)始找,如果找不到再?gòu)膕cope chain的第二個(gè)對(duì)象找, global對(duì)象始終是scope chain 的最后一個(gè)對(duì)象,如果global object中也找不到屬性,那為undefined.
有兩個(gè)注意點(diǎn):
   如果可能,這個(gè)查找過(guò)程會(huì)對(duì)對(duì)象的prototype(原型對(duì)象)查找。先找實(shí)例屬性,再找原型屬性。見(jiàn)我的其它文章
   在函數(shù)內(nèi),這個(gè)函數(shù)的調(diào)用對(duì)象包括的參數(shù),local變量,inner函數(shù)等

本站僅提供存儲(chǔ)服務(wù),所有內(nèi)容均由用戶發(fā)布,如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊舉報(bào)。
打開(kāi)APP,閱讀全文并永久保存 查看更多類似文章
猜你喜歡
類似文章
JavaScript中的作用域鏈和閉包
Javascript Closures
JS
深入理解JavaScript閉包(closure) – Felix Woo
圖靈社區(qū) : 閱讀 : OOP與jQuery(四):函數(shù)作用域、方法連綴及jQuery.fn
JS閉包
更多類似文章 >>
生活服務(wù)
分享 收藏 導(dǎo)長(zhǎng)圖 關(guān)注 下載文章
綁定賬號(hào)成功
后續(xù)可登錄賬號(hào)暢享VIP特權(quán)!
如果VIP功能使用有故障,
可點(diǎn)擊這里聯(lián)系客服!

聯(lián)系客服