JavaScript 範圍鏈解析

來源:互聯網
上載者:User

最近看了下JavaScript方面的幾本書,把裡面的一些核心概念按照自己的理解做個總結。

 

JavaScript中有Scope(範圍),Scope chain(範圍鏈),Execute context(執行內容),Active Object (使用中的物件),Dynamic Scope(動態範圍),Closure(閉包)這些概念,要理解這些概念,我們從靜態和動態兩個方面去分析一下。

首先我們寫一個簡單的function來做一個例子:

function add(num1, num2){

var sum = num1 + num2;

return sum;

}

我們定義了一個具有兩個形參的add函數。

靜態方面:

當建立add函數的時候,Javascript引擎會建立add函數的Scope chain,這個範圍鏈指向了Global Context(全域上下文)。如果用圖形形象化的表述如所示:

 

從可以看出,當add函數建立的時候,範圍鏈就已經建立了,因此可以得出一個結論,函數的範圍鏈是建立函數的時候就已經建立了,而不是動態運行期。下面就來看看動態運行期的時候會發生什麼事情。

 

動態方面:

當執行add函數的時候,JavaScript會建立一個Execute context(執行內容),執行內容中就包含了add函數運行期所需要的所有資訊。Execute context也有自己的Scope chain,當函數啟動並執行時候,JavaScript引擎會首先從用add函數的範圍鏈來初始化執行內容的範圍鏈,然後JavaScript引擎又會建立一個Active Object,這個對象裡麵包含了函數運行期的所有局部變數,參數以及this等變數。

如果形象的描述add函數動態運行期會發生什麼,可以用如來描述:


 從可以看出,執行內容是一個動態概念,它是當函數啟動並執行時候建立的,同時Active Object對象也是一個動態概念,它是被執行內容的範圍鏈引用的。因此可以得出一個結論:執行內容和使用中的物件都是動態概念,並且執行內容的範圍鏈是由函數範圍鏈初始化的。

上面說了函數範圍和執行內容範圍,下面接著說一下動態範圍的問題,當在JavaScript通過with語句,try-catch的catch子句,以及eval方法的時候,JavaScript引擎就會動態改變執行內容的範圍。下面還是通過一個例子來看看:

function initUI(){

with (document){ //avoid!

var bd = body,

links = getElementsByTagName("a"),

i= 0,

len = links.length;

while(i < len){

update(links[i++]);

}

getElementById("go-btn").onclick = function(){

start();

};

bd.className = "active";

}

當執行上面的initUI函數的時候,JavaScript會動態建立一個with 語句對應的範圍放到執行內容範圍鏈的最前端,通過可以形象的描述上述過程,紅色標註的地區就顯示了with語句產生的範圍。


 最後,我們來看看JavaScript最神秘的Closure(閉包),閉包在JavaScript其實就是一個函數,閉包是在函數運行期被建立的,下面還是以一個執行個體來看看:

function assignEvents(){

var id = "xdi9592";

document.getElementById("save-btn").onclick = function(event){

saveDocument(id);

};

}

當上面的assignEvents函數被執行的時候,會建立一個閉包,而這個閉包會引用assignEvents範圍中的id變數,如果按照傳統的程式設計語言的方式,id是儲存在堆棧上的一個變數,當函數執行完了以後id就消失,那麼怎麼可能再次引用呢?顯然這裡JavaScript採用了另外的方式。下面就來看看JavaScript是如何來實現閉包的。當執行assignEvents函數的時候,JavaScript引擎會建立函數範圍鏈,這個範圍鏈包含了assignEvents執行時的使用中的物件,而同時JavaScript引擎也會建立一個閉包,而閉包的範圍鏈也會引用assignEvent執行時候的使用中的物件,這樣當assignEvents執行完的時候,雖然它本身執行內容的範圍鏈不再引用使用中的物件了,但是閉包還是引用著assignEvents運行期對應的使用中的物件,這就解釋了JavaScipt內部的閉包機制。可以用形象的表述上面assignEvents函數運行期的情形:


    從上面可以看出,當assignEvents函數執行完畢以後,document.getElementById("save-btn").onclick 引用了閉包,這樣當使用者點擊save-btn的時候,就會觸發閉包的執行,那麼下面就來看看閉包執行時的情形。前面也說了JavaScript中閉包其實就是函數,因此閉包執行和函數執行時的情形是一致的,通過來形象的描述上述onclick事件所關聯的閉包。

 

 


 從可以看出JavaScript引擎首先建立了閉包的執行內容,然後用閉包範圍鏈來初始化閉包的執行內容範圍鏈,最後再將閉包執行時對應的使用中的物件放入到範圍的最前端,這也進一步驗證了閉包就是函數的論斷。

 

參考資料:

1.High Performance JavaScript. http://book.douban.com/subject/5362856/

2.JavaScript進階程式設計. http://book.douban.com/subject/4886879/

 

轉載:

http://www.starming.com/index.php?action=plugin&v=wave&tpl=union&ac=viewgrouppost&gid=119&tid=17313

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.