JS 總結之變量對象

就如上一篇《JS 總結之閉包》中談到的,閉包的造成是變量對象和做用域鏈共同做用的結果。html

什麼是變量對象?變量對象是執行環境的一個屬性,儲存在與執行環境相關的變量和函數聲明。git

🥇 不一樣執行環境中的變量對象

根據執行環境的不一樣,可分爲全局執行環境的變量對象和函數執行環境的變量對象。github

🤺 全局執行環境

首先咱們須要理解如下幾個概念:瀏覽器

🥛 Global 對象

Global 對象能夠說是 ECMAScript 中最特別的一個對象了,由於無論你從什麼角度上看,這個對象都是不存在的。ECMAScript 中的 Global 對象在某種意義上是做爲一個終極的「兜底兒對象」來定義的。換句話說,不屬於其餘對象的屬性和方法,最終都是它的屬性和方法。閉包

事實上,沒有全局變量或全局函數,全部在全局做用域中定義的屬性和函數,都是 Global 對象的屬性函數

🍺 window 對象

在瀏覽器中,window 對象有着雙重角色,既是經過 JavaScript 訪問瀏覽器窗口的一個接口,又是 ECMAScript 規定的 Global 對象spa

ECMAScript 雖然沒有指出如何直接訪問 Global 對象,可是 Web 瀏覽器都是將這個 Global 對象做爲 window 對象的一部分加以實現的。所以,在全局做用域中聲明的全部變量和函數,就都成爲了 window 對象的屬性。設計

🍷 全局執行環境

在 Web 瀏覽器中,全局執行環境被認爲是 window 對象,所以,全部全局變量和函數都是做爲 window 對象的屬性和方法建立的。全局執行環境直到應用程序退出(如關閉網頁或瀏覽器)時纔會摧毀。code

☕️ 全局執行環境中的變量對象

綜上所述,能夠理解爲,全局做用域 == window 對象 == Global 對象。而變量對象是爲了找到屬性和方法,因此,全局執行環境中的變量對象(Variable Object,縮寫爲 VO)只能是 Global 對象了,由於能在上面找到屬性和方法。xml

⛹ 函數執行環境

在函數執行環境中,全局執行環境的變量對象 VO 不能直接訪問,此時由激活對象(Activation Object,縮寫爲 AO)扮演 VO 的角色。

激活對象 AO 是在進入函數執行環境時刻被建立的,它經過函數的 arguments 屬性初始化。arguments 屬性的值是 Arguments 對象。

對於 VO 和 AO 的關係能夠理解爲,VO 在不一樣的 Execution Context 中會有不一樣的表現:當在全局執行環境中,能夠直接使用 VO;可是,在函數執行環境中,AO 就會被建立。

當函數執行完後,函數執行環境被摧毀,變量對象也會隨之摧毀。

🥈 處理代碼

全局執行環境和函數執行環境對代碼處理都是同樣的,分紅兩個基本的階段來處理:

  1. 創建階段
  2. 執行階段

🍼 創建階段

當創建階段(代碼執行以前)時,VO 裏已經包含了下列屬性(前面已經說了):

  1. 函數的全部形參(函數執行上下文中)
    • 變量對象以名字爲屬性名,值爲屬性值建立屬性;
    • 若是沒有對應的參數的話,屬性值爲 undefined。
  2. 全部函數聲明
    • 由名稱和對應值(函數對象(function-object))組成一個變量對象的屬性被建立;
    • 若是變量對象已經存在相同名稱的屬性,則徹底替換這個屬性。
  3. 全部變量聲明
    • 由名稱和對應值(undefined)組成一個變量對象的屬性被建立;
    • 若是變量名稱跟已經聲明的形式參數或函數相同,則變量聲明不會干擾已經存在的這類屬性。

(注意:未聲明的變量不會放入變量對象中

讓咱們看一個例子:

function test(a) {
  var b = 10
  function c() {}
  var d = function _e() {}
}

test(10) // call
複製代碼

當進入帶有參數 10 的 test 函數上下文時,AO 表現爲以下:

AO(test) = {
  arguments: {
    0: 1,
    length: 1
  },
  a: 1,
  b: undefined,
  c: <reference to FunctionDeclarationc’>, d: undefined, } 複製代碼

☕️ 執行階段

根據代碼的執行順序,修改變量對象的值,上面的例子變爲:

AO(test) = {
  arguments: {
    0: 1,
    length: 1
  },
  a: 1,
  b: 10,
  c: <reference to FunctionDeclaration ‘c’>,
  d: <reference to FunctionExpression ‘_e’>,
}
複製代碼

至此,變量對象就生成完畢。

🚀 參考

相關文章
相關標籤/搜索