JavaScript: ----深入理解JS執行上下文(二)
上篇文章我們了解到:js解析器會在(全局代碼/函數/eval代碼)執行前創建一個與之對應的執行上下文,
而對於每個執行上下文,都會有三個重要屬性:
- 變量對象(Variable object,VO)
- 作用域鏈(Scope chain)
- this
這篇文章講的是第一個,變量對象(Variable object,VO)。
什麽是變量對象:
變量對象是與執行上下文相關的數據作用域,存儲了在上下文中定義的變量和函數聲明。
不同執行上下文下的變量對象稍有不同,所以我們來聊聊全局上下文下的變量對象和函數上下文下的變量對象。
全局上下文中的變量對象:
全局對象是預定義的對象
在頂層 JavaScript 代碼中,可以用關鍵字 this 引用全局對象。因為全局對象是作用域鏈的頭,這意味著所有非限定性的變量和函數名都會作為該對象的屬性來查詢。
函數上下文中的變量對象:
在函數上下文中,我們用活動對象(activation object, AO)來表示變量對象。
活動對象和變量對象其實是一個東西,只是變量對象是規範上的或者說是引擎實現上的,不可在 JavaScript 環境中訪問,只有到當進入一個執行上下文中,這個執行上下文的變量對象才會被激活
活動對象是在進入函數上下文時刻被創建的,它通過函數的 arguments 屬性初始化。arguments 屬性值是 Arguments 對象。
執行上下文中的執行過程:
執行上下文的代碼會分成兩個階段進行處理:分析和執行,我們也可以叫做:
- 進入執行上下文(分析代碼)
- 代碼執行
進入執行上下文
當進入執行上下文時,這時候還沒有執行代碼,
變量對象會包括:
-
函數的所有形參 (如果是函數上下文)
- 由名稱和對應值組成的一個變量對象的屬性被創建
- 沒有實參,屬性值設為 undefined
-
函數聲明
- 由名稱和對應值(函數對象(function-object))組成一個變量對象的屬性被創建
- 如果變量對象已經存在相同名稱的屬性,則完全替換這個屬性(函數優先)
-
變量聲明
- 由名稱和對應值(undefined)組成一個變量對象的屬性被創建;
- 如果變量名稱跟已經聲明的形式參數或函數相同,則變量聲明不會幹擾已經存在的這類屬性
舉個例子:
function foo(a) { var b = 2; function c() {} var d = function() {}; b = 3; } foo(1);
在進入執行上下文後,這時候的 AO 是:
AO = { arguments: { 0: 1, length: 1 }, a: 1, b: undefined, c: reference to function c(){}, d: undefined }
代碼執行
在代碼執行階段,會順序執行代碼,根據代碼,修改變量對象的值
還是上面的例子,當代碼執行完後,這時候的 AO 是:
AO = { arguments: { 0: 1, length: 1 }, a: 1, b: 3, //先賦值為2,又賦值為3 c: reference to function c(){}, d: reference to FunctionExpression "d" //指向匿名函數 }
原文鏈接: https://github.com/mqyqingfeng/Blog/issues/5
JavaScript: ----深入理解JS執行上下文(二)