執行環境是ECMAScript規範(ECMA 262第三版)使用的抽象概念,用於定義ECMAScript實現的必要行為。規範中沒有關於如何實現執行環境的規定。但是,因為執行環境包含引用規範定義的結構的相關屬性,所以具有屬性的對象應該在執行環境中維護(甚至實現)——即使屬性不是公共的。
所有JavaScript代碼都在執行環境中執行。全局代碼(作為內置JS文件執行的代碼或由HTML頁面加載的代碼)
它是在我稱之為“全局執行環境”的環境中執行的,每壹次調用壹個函數(可能作為構造函數)也有壹個相關的執行環境。及格
當壹個JavaScript函數被調用時,該函數會進入相應的執行環境。如果調用另壹個函數(或者遞歸調用同壹個函數),就會創建壹個新的執行環境,在函數調用過程中,執行過程就在這個環境中。當被調用的函數返回時,執行過程將返回到原來的執行環境。因此,運行的JavaScript代碼構成了壹個執行環境堆棧。
在創建執行環境的過程中,會按照定義的順序完成壹系列操作。首先,在函數的執行環境中,創建壹個“活動”對象。活動對象是規範中規定的另壹種機制。之所以稱之為對象,是因為它有可訪問的命名屬性,但它不像普通對象那樣有原型(至少沒有預定義的原型),也不能通過JavaScript代碼直接引用活動對象。
為函數調用創建執行環境的下壹步是創建arguments對象,這是壹個類似數組的對象,它保存調用函數時傳遞的參數,這些參數與由整數索引的數組成員壹壹對應。這個對象還有length和callee屬性(這兩個屬性與我們討論的內容無關,詳見規範)。然後,為活動對象創建壹個名為“arguments”的屬性,該屬性引用前面創建的arguments對象。
接下來,給執行環境分配壹個範圍。作用域由對象列表(鏈)組成。每個函數對象都有壹個內部的[[scope]]屬性(我們後面會詳細介紹),這個屬性也由壹個對象列表(鏈)組成。分配給函數調用執行環境的作用域由函數對象的[[scope]]屬性引用的對象列表(鏈)組成,同時將活動對象添加到對象列表的頂部(鏈的前端)。
那麽將發生由ECMA 262中的所謂“變量”對象完成的“變量實例化”過程。此時只使用活動對象作為可變對象(這裏很重要,請註意它們是同壹個對象)。這時,函數的形參將被創建為名為attributes的變量對象。如果調用函數時傳遞的參數與形參壹致,則相應參數的值將賦給這些命名屬性(否則,未定義的值將賦給命名屬性)。對於已定義的內部函數,將為聲明時使用的名稱的可變對象創建壹個同名的屬性,相應的內部函數將被創建為function對象並賦給該屬性。變量實例化的最後壹步是創建所有在函數內部聲明的局部變量,作為可變對象的命名屬性。
在變量實例化期間,根據聲明的局部變量創建的變量對象的屬性將被賦予未定義的值。在執行函數體中的代碼並計算相應的賦值表達式之前,局部變量不會被實例化。
實際上,帶有arguments屬性的活動對象和與函數的局部變量相對應的帶有named屬性的變量對象是同壹個對象。因此,標識符參數可以被視為函數的局部變量。