javascript函數的定義與執行

來源:互聯網
上載者:User

標籤:

要理解javascript函數的定義與執行,首先需要知道這幾個重要的概念,現在可以Crowdsourced Security Testing道稍後再理解!

函數的執行環境(excution context)、使用中的物件(call object)、範圍(scope)、範圍鏈(scope chain)。  接下來,我們以這個函數為例進行分析:  步驟: 1、設定範圍鏈當定義函數a的時候,JS解譯器會將函數a的 範圍鏈(scope chain)設定為 “定義a時a所在的環境”,此處a第一個添加的範圍是window對象。(如果a是一個全域函數,則scope chain中只有window對象。) 個人見解:範圍鏈裡面其實是包含的使用中的物件,使用中的物件可以理解為是用來識別範圍的。(就像是一個商場分為A、B、C  三個區,就可以理解為在這個商場的範圍鏈裡面,有A、B、C 3個使用中的物件,3個範圍!(“個人見解,可能不恰當”)。 2、執行環境當執行函數a的時候,a會進入相應的執行環境(excution context)。 個人見解:建立執行環境分為 建立範圍建立使用中的物件兩步。 3、範圍當建立執行環境的過程中,首先會為a 添加一個scope屬性,即a的範圍,其值就是第一步中的scope chain。即a.scope = a的範圍鏈。 個人見解:可以把範圍和範圍鏈理解成是名字不同但作用相同! 4、建立使用中的物件建立完範圍,緊接著執行環境會 建立一個使用中的物件(call object)。使用中的物件也是一個擁有屬性的對象,但它不具有原型而且不能通過javascript代碼直接存取(可以看下面的圖或者個人見解理解)。 建立完使用中的物件後,把使用中的物件添加到a的範圍鏈的最頂端。此時a的範圍鏈包含兩個對象:a的使用中的物件和window對象。下一步是在使用中的物件上添加一個arguments屬性,它儲存著調用函數a時所傳遞的參數。最後所有的函數a的形參和內部的函數b的引用也被添加到a的使用中的物件上。在這一步中,完成了函數b的定義,因此如同第3步,函數b的範圍被設定為b所定義的環境,即a的範圍。(就類似於a的範圍鏈中第一個加入的範圍是window對象。)! 個人見解:(1) 使用中的物件是一個為了理解而添加的名詞,實際不存在,所以不具有原型、也不能用實際代碼訪問。(類似於磁感線,只是為了描述)  完結:到此,整個函數a從定義到執行的步驟就完成了。此時a返回b的引用給c,又因為函數b的範圍鏈包含了函數a的使用中的物件的引用,也就是說b中可以訪問到a中定義的所有變數和函數。又函數b被c引用,函數b依賴於a,因此函數a再返回後不會被GC回收(參考最下方javascript的記憶體回收機制)! 當函數b被執行的時候也會像以上步驟一樣。因此執行時b的範圍鏈包含了3個對象:b的使用中的物件,a的使用中的物件,window對象,: ,當在函數b訪問一個變數的時候,搜尋順序是:b的使用中的物件 —>b的原型對象(存在的話)—>a的使用中的物件 —>window對象 變數尋找機制:先尋找自身的使用中的物件,如果存在則返回,如果不存在且該函數存在prototype原型對象,則尋找原型對象。依次尋找a的使用中的物件、window對象。直到找到為止,如果整個範圍鏈上沒有找到,則返回undefined。 總結:以上提到了兩個重要的詞語:函數的定義與執行。文中提到 函數的範圍是在定義函數的時候就已經確定,而不是在執行的時候確定(參看步驟1和3).用一段代碼來說明這個問題:
1 function f(x){2   var g = function(){ return x;}3    return g;4 }5  var h = f(1);6 alert(h());
這段代碼中變數h指向了f中的那個匿名函數(由g返回,也可以理解為不匿名,因為有名字g(不正規理解))。(1)h的範圍在定義的時候確定:個人理解h的範圍鏈:g的使用中的物件->f的使用中的物件->window對象(因為此處h代表的是返回的"g()"函數,既然是定義為準,就應該是定義"g()"函數時確定,所以 h.scope chain = g.scope chain )網上參考h的範圍鏈:h的使用中的物件 ->f的使用中的物件->window對象(2)h的範圍在執行(alert( h ( ) )的時候確定:h的範圍鏈:h的使用中的物件->alert的使用中的物件->window對象。 結果:(1)應該輸出1 (2)應該輸出undefined  。實踐證明函數的範圍是在定義這個函數的時候就已經確定了! 

補充:Javascript的記憶體回收機制

在Javascript中,如果一個對象不再被引用,那麼這個對象就會被GC回收。如果兩個對象互相引用,而不再被第3者所引用,那麼這兩個互相引用的對象也會被回收。因為函數a被b引用,b又被a外的c引用,這就是為什麼函數a執行後不會被回收的原因。

function a(){

var i = 0;

var b = function(){ alert(++i);}

return b;

}

var c = a();

c();

以上代碼如果沒有return b; 當函數a執行完後就會被回收!兩個對象互相引用(a引用b,b引用a),而不再被第3者所引用(沒有返回資料給c),那麼這兩個互相引用的對象也會被回收。

 參考文檔:http://www.jb51.net/article/24101.htm  (javascript深入理解js閉包)

javascript函數的定義與執行

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.