西西軟件園多重安全檢測下載網(wǎng)站、值得信賴的軟件下載站!
軟件
軟件
文章
搜索

首頁編程開發(fā)javascript|JQuery → JavaScript學習之旅——從Scope Chain到Closure

JavaScript學習之旅——從Scope Chain到Closure

相關軟件相關文章發(fā)表評論 來源:本站整理時間:2010/9/5 20:48:06字體大。A-A+

作者:佚名點擊:372次評論:1次標簽: global JS

  • 類型:行業(yè)軟件大小:14.6M語言:中文 評分:2.2
  • 標簽:
立即下載

a = 1;
function Outer(x){
      function Inner(y){return x + y;}
      return Inner
}
var inner = Outer(1);
inner(2);

執(zhí)行上面這段代碼的過程中,有哪些事情發(fā)生?Inner函數(shù)為什么可以引用Outer函數(shù)的參數(shù)x?closure是怎么實現(xiàn)的?本文試圖回答這些問題。

術語

本文雖然所講理論并不復雜,但用到不少名詞,初讀時相對比較晦澀,下面列出術語和簡短解釋,便于閱讀時隨時查看。

  • global:engine預先創(chuàng)建好的一個object,里面有所有built-in objects的屬性。
  • globalContext:本文術語,用作表示全局的execution context。
  • globalScopeChain:本文術語,用作表示全局的execution context所擁有的Scope Chain,里面只有一個對象為global,用代碼表示為 [global]
  • functionContext:本文術語,用作表示執(zhí)行函數(shù)代碼時,進入的新的execution context。
  • VariableObject:ECMAScript術語,在globalContext中即為global,在functionContext中是被創(chuàng)建的一個對象。在進入context時,被放到scope chain的最前方。
  • outerVariable:本文術語,表示進入OuterFunctionContext時被創(chuàng)建的Variable Object。
  • innerVariable:本文術語,表示進入InnerFunctionContext時被創(chuàng)建的Variable Object。
  • outerFunctionContext:本文術語,用作表示執(zhí)行Outer這個函數(shù)時,進入的execution context。
  • outerScopeChain:本文術語,用作表示outerFunctionContext所擁有的Scope Chain?捎肹outerVariable, global]表示。
  • innerFunctionContext:本文術語,用作表示執(zhí)行Inner這個函數(shù)時,進入的execution context。
  • innerScopeChain:本文術語,用作表示innerFunctionContext所擁有的Scope Chain?捎肹innerVariable, outerVariable, global]表示。

 JS代碼種類

JS代碼分三種:

  1. Global code,全局代碼
  2. Functioncode,函數(shù)內(nèi)的代碼。
  3. Eval code,為簡單計,不在本文說明。

Execution context

任何一句JS代碼,都是執(zhí)行在一個特定的“execution context”下面。

執(zhí)行Global code時,JavaScript engine將會創(chuàng)建一個全局的context,為表述簡單,我們把它叫做globalContext。

而每次進入Functioncode時,將會創(chuàng)建一個新的context,在函數(shù)返回(或有未捕獲的異常發(fā)生)時,退出這個新的context,本文把它叫做functionContext。

 a = 1; //進入globalContext

function Outer(x){
function Inner(y){return x + y;}
return Inner
} //在globalContext中創(chuàng)建Outer這個Function

var inner = Outer(1); //執(zhí)行Outer函數(shù)時進入新創(chuàng)建的outerFunctionContext上下文。

            //然后退出,回到globalContext,把Outer(1)的返回值賦給inner這個變量。
inner(2); //進入InnerContext,執(zhí)行Inner函數(shù)的return x + y,然后退出,回到globalContext

Scope Chain

每個execution context都有一個關聯(lián)的Scope Chain。所謂Scope Chain,其實就是一個List,里面有若干個object。

 global

globalContext所關聯(lián)的Scope Chain,這里不妨稱之為globalScopeChain,這個chain里面只有一個object,就是global,global是一個engine事先創(chuàng)建好的對象,所有的built-in Object(比如Function()、Object()、Math)都會作為這個global對象的屬性。

 Function型對象的[[Scope]]屬性

在第一篇創(chuàng)建Function型對象的步驟里,第5步說了,會為這個Function型對象創(chuàng)建一個[[Scope]]屬性,不過當初沒有提到,這個屬性的值是當前context的Scope Chain。

Outer函數(shù)是在globalContext下創(chuàng)建起來的,因此Outer.[[Scope]] = globalScopeChain,也就是[global]。而Inner函數(shù)是在執(zhí)行Outer函數(shù)時,也就是在outerFunctionContext下創(chuàng)建起來的,因此Inner.[[Scope]] = OuterContext的ScopeChain,是什么呢,往下看。

 Entering execution context

每次進入一個context(不管是globaContext還是functionContext)時,都會有一系列的事情發(fā)生。

  1. 上面說到,每個context都有一個關聯(lián)的Scope Chain,這個Scope Chain就是在此時會被創(chuàng)建起來的。
  2. 確定或創(chuàng)建一個Variable Object(ECMAScript術語),并把它放到Scope Chain的最前面。
    對于globalContext,這個Variable Object就是global,被放到globalScopeChain里(也是globalScopeChain里唯一的一個對象);
    而如果進入到一個functionContext,則會創(chuàng)建一個Variable Object起來,也放到Scope Chain的最前面,并且還會額外再做一件事——就是把當前Function的[[Scope]]里所有object,放到Scope Chain里面。因此執(zhí)行Outer函數(shù)時,Scope Chain是這樣的:[outerVariable, global];上面知道,創(chuàng)建Inner函數(shù)時,這個Chain將作為Inner函數(shù)的[[Scope]]屬性,因此進入Inner函數(shù)的執(zhí)行時,它的Scope Chain就是[innerVariable, outerScopeChain],也就是[innerVariable, outerVariable, global]。
  3. 實例化Variable Object,就是為Variable Object創(chuàng)建一些屬性。
    首先,如果是functionContext,則把函數(shù)的參數(shù)作為Variable Object的屬性;
    其次,把聲明的函數(shù)作為Variable Object的屬性;這里的屬性將覆蓋上面的同名屬性。
    再次,把聲明的變量作為Variable Object的屬性,屬性的初始值均為undefined,只有在執(zhí)行賦值語句后,才會有值。這邊的屬性不會覆蓋上面的同名屬性。
  4. 為當前context確定this,this在context中是不變的。
    詳細見下面的注解。

//在執(zhí)行一切代碼之前,進入globalContext,global對象也已經(jīng)創(chuàng)建好。
 

//1.然后創(chuàng)建Scope Chain
globalContext.ScopeChain = [];

//2.確定variable object為global,并加入到scope chain中
variable = global;
globalContext.ScopeChain.push(global);

//3.實例化variable object,創(chuàng)建a、Outer和inner三個屬性,初始值為null。
variable.a = null;
variable.Outer = null;
variable.inner = null;

//4.確定this,在globalContext中為global。
this = global;

//以上是進入globalContext時所做的事情  
//以下開始執(zhí)行代碼。
  a = 1;   function Outer(x){
  function Inner(y){return x + y;}
  return Inner
  }    //對于以上這段代碼,發(fā)生的事用偽代碼表示如下:
//創(chuàng)建Outer函數(shù),傳入當前的scope chain,即[global]
Outer = new Function('', '' [global])
//為Outer.[[Scope]]賦值
Outer.[[Scope]] = [];
Outer.[[Scope]].push(global);
//這時variable的屬性Outer就指向這個函數(shù)了,不再是null。
variable.Outer = Outer

  var inner = Outer(1); //這段代碼用偽代碼表示如下:
//執(zhí)行Outer函數(shù),進入新創(chuàng)建的outerFunctionContext上下文
//1.創(chuàng)建ouerFunctionContext的Scope Chain,并放入Outer函數(shù)的[[Scope]]力所有的object
outerFunctionContext.ScopeChain = [];
outerFunctionContext.ScopeChain.push(global) //global是[[Scope]]里唯一的對象。
//2.創(chuàng)建Variable Object屬性,并放到Scope Chain的最前方。
outerVariable= {arguments: xxx} //創(chuàng)建的variable有arguments等屬性
outerFunctionContext.ScopeChain.push(variable)
//3.實例化variable object
outerVariable.x = 1
outerVariable.Inner = new Function('y', 'return x + y', [outerVariable, global])   //注意上句創(chuàng)建Inner函數(shù)時,會傳入當前的Scope Chain,即[outerVariable, global]  //4.確定Outer函數(shù)體內(nèi)的this參數(shù),就是新創(chuàng)建的函數(shù)對象。
//最后回到globalContext中,把新建的Inner函數(shù)對象,返回給inner變量。

  inner(2); //最后執(zhí)行的這句代碼,將創(chuàng)建并進入InnerContext。

初步結論

現(xiàn)在已經(jīng)知道,執(zhí)行Outer函數(shù)時,對應的outerScopeChain的圖如下,注意global對象忽略了指向所有built-in object的屬性:

  

執(zhí)行Inner函數(shù)時,對應的innerScopeChain的圖如下:

  

Scope Chain的作用

Scope chain的圖出來了,那么它用來干嘛呢?執(zhí)行inner函數(shù)的return x + y,會發(fā)現(xiàn),我們需要兩個變量,x和y。那么JavaScript將循著Scope Chain來查找,與__proto__鏈配合,也就是首先在innerVariable(以及其__proto__鏈)找x,沒找到,則到outerVariable中找x,找到為1。 找y時類似。這就是Inner函數(shù)體中,可以訪問得到Outer函數(shù)中定義的參數(shù)x的原理所在,不難想象,如果Outer函數(shù)中定義了局部變量z,那么z也會出現(xiàn)在outerVariable對象中,因此同樣可以被Inner函數(shù)訪問。內(nèi)部函數(shù)可以引用外部函數(shù)的參數(shù)以及變量,這就是JavaScript傳說中的閉包(Closure)。

    相關評論

    閱讀本文后您有什么感想? 已有人給出評價!

    • 8 喜歡喜歡
    • 3 頂
    • 1 難過難過
    • 5 囧
    • 3 圍觀圍觀
    • 2 無聊無聊

    熱門評論

    最新評論

    發(fā)表評論 查看所有評論(1)

    昵稱:
    表情: 高興 可 汗 我不要 害羞 好 下下下 送花 屎 親親
    字數(shù): 0/500 (您的評論需要經(jīng)過審核才能顯示)