JS 總結之變量對象

clipboard.png

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

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

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

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

🤺 全局執行環境

首先我們需要理解以下幾個概念:

🥛 Global 對象

Global 對象可以說是 ECMAScript 中最特別的一個對象了,因爲不管你從什麼角度上看,這個對象都是不存在的。ECMAScript 中的 Global 對象在某種意義上是作爲一個終極的“兜底兒對象”來定義的。換句話說,不屬於其他對象的屬性和方法,最終都是它的屬性和方法。

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

🍺 window 對象

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

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

🍷 全局執行環境

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

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

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

⛹ 函數執行環境

在函數執行環境中,全局執行環境的變量對象 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 FunctionDeclaration ‘c’>,
  d: undefined,
}

☕️ 執行階段

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

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

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

🚀 參考

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章