轉自 http://www.jb51.net/article/30706.htm
作用域鏈(scope chain)
JavaScript中,JavaScript裏一切都是對象,包括函數。函數對象和其它對象一樣,擁有可以通過代碼訪問的屬性和一系列僅供JavaScript引擎訪問的內部屬性。其中一個內部屬性是作用域,包含了函數被創建的作用域中對象的集合,稱爲函數的作用域鏈,它決定了哪些數據能被函數訪問。
當一個函數創建後,它的作用域鏈會被創建此函數的作用域中可訪問的數據對象填充。例如函數:
function add(num1,num2) {
var sum = num1 + num2;
return sum;
}
在函數add創建時,它的作用域鏈中會填入一個全局對象,該全局對象包含了所有全局變量,如下圖所示(注意:圖片只例舉了全部變量中的一部分):
由此可見,函數的作用域鏈是創建函數的時候創建的。
執行上下文(Execute context )
函數add的作用域將會在執行時用到,例如:
var total = add(5,10);
當執行 add 函數的時候, JavaScript 會創建一個 Execute context (執行上下文),執行上下文中就包含了 add 函數運行期所需要的所有信息。 Execute context 也有自己的 Scope chain, 當函數運行時, JavaScript 引擎會首先從用 add 函數的作用域鏈來初始化執行上下文的作用域鏈。
活動對象(Active Object)
然後 JavaScript 引擎又會創建一個 Active Object, 這些值按照它們出現在函數中的順序被複制到執行期上下文的作用域鏈中,它們共同組成了一個新的對象——“活動對象(activation object)”,這個對象裏面包含了函數執行期的所有局部變量,參數以及 this 等變量,此對象會被推入作用域鏈的前端,當執行期上下文被銷燬,活動對象也隨之銷燬。(函數每次執行時對應的執行期上下文都是獨一無二的,所以多次調用同一個函數就會導致創建多個執行期上下文,當函數執行完畢時,執行期上下文就被銷燬)新的作用域鏈如下圖所示:
執行上下文是一個動態的概念,當函數運行的時候創建,活動對象 Active Object 也是一個動態的概念,它是被執行上下文的作用域鏈引用的,可以得出結論:執行上下文和活動對象都是動態概念,並且執行上下文的作用域鏈是由函數作用域鏈初始化的。
在函數執行過程中,每遇到一個變量,都會檢索從哪裏獲取和存儲數據,該過程從作用域鏈頭部,也就是從活動對象開始搜索,查找同名的標識符,如果找到了就使用這個標識符對應的變量,如果沒有則繼續搜索作用域鏈中的下一個對象,如果搜索完所有對象都未找到,則認爲該標識符未定義,函數執行過程中,每個標識符都要經歷這樣的搜索過程。
舉個栗子
function newLoad(){ //新建頁面加載的事件
for (var i = 1; i <=3; i++) {
var anchor = document.getElementById("anchor" + i); //找到每個anchor
anchor.onclick = function () {//爲anchor添加單擊事件
alert ("you clicked anchor"+i);//給出點擊反應
}
}
}
window.onload = newLoad; //把newload事件賦值給頁面加載
</script>
前臺代碼:
<body>
<a id="anchor1" href="#">anchor1</a><br/>
<a id="anchor2" href="#">anchor2</a><br/>
<a id="anchor3" href="#">anchor3</a><br/>
</body>
結果分析
anchor.onclick這個函數的作用域在全局,所以一旦他執行他的執行期上下文會拷貝一份他的當前作用域所包含的對象到自己的執行器上下文中用於初始化,然後創建一個Active Object對象,這裏的i = 4,是從Global object中找到的,從這裏也推測出,數據訪問的作用域鏈的深度會存在性能損失(假如你有個局部變量i那就再active object中找到了)