個人理解:
執行環境的概念:每個函數在調用的時候會建立一個自己的執行環境。當執行流進入一個函數的時候,函數的環境就會被推入一個環境棧,而在函數執行之後,棧將其執行環境彈出,並將控制權移交給之前的執行環境。執行環境定義了變數和函數有權訪問的其他資料,並定義了他們各自的行為;
變數對象:當函數被調用的時候,每個執行環境都會有一個與之相關的變數對象,環境中定義的所有變數和對象都儲存在這個對象。
變數對象(variable object) 是與執行內容相關的 資料範圍(scope of data) 。 它是與上下文關聯的特殊對象,用於儲存被定義在上下文中的 變數(variables) 和 函式宣告(function declarations) 。 它是一個抽象的概念,不同的上下文中,它表示使用不同的object。例如,在global全域上下文中,變數對象也是全域對象自身[global object]。(這就是我們可以通過全域對象的屬性來指向全域變數)。
範圍鏈:在一個函數被建立的時候,會建立一個預先包含全域變數對象的範圍鏈,並把這個範圍鏈儲存於內部的【Scope】屬性中;所以說建立任何一個函數的時候就會建立包含全域變數對象的範圍鏈;
當函數第一次被調用的時候,會建立一個執行環境以及相應的範圍鏈,然後通過複製函數的【scope】屬性中的對象構建起執行環境的範圍鏈,然後又有一個使用中的物件(這裡作為變數對象)被建立並被推入執行環境範圍鏈的前端,最後使用this,arguments,和其他具名引數來初始化函式活動對象(如果是函數,則將其使用中的物件作為變數對象);
性質:1,範圍鏈的前端始終都是當前執行代碼所在環境的變數對象
2,全域執行環境的的變數對象之中都是範圍鏈的最後一個變數對象;
3,範圍鏈的作用在於保證對執行環境中有權訪問的所有變數和函數的順序訪問;
4,內部環境變數可以通過範圍鏈訪問所有的外部環境,但是外部環境不能訪問內部環境的任何變數和函數;
5,範圍鏈本質是一個指向變數對象的指標列表,他只引用但不實際包含變數對象。
度娘精選:
執行內容棧:注意,一個function可能產生無限的上下文環境,因為一個函數的調用(甚至遞迴)都產生了一個新的上下文環境。
一系列活動的執行內容從邏輯上形成一個棧。棧底總是全域上下文,棧頂是當前(活動的)執行內容。當在不同的執行內容間切換(退出的而進入新的執行內容)的時候,棧會被修改(通過壓棧或者退棧的形式)。
當javascript代碼檔案被瀏覽器載入後,預設最先進入的是一個全域的執行內容。當在全域上下文中調用執行一個函數時,程式流就進入該被調用函數內,此時引擎就會為該函數建立一個新的執行內容,並且將其壓入到執行內容堆棧的頂部。瀏覽器總是執行當前在堆棧頂部的上下文,一旦執行完畢,該上下文就會從堆棧頂部被彈出,然後,進入其下的上下文執行代碼。這樣,堆棧中的上下文就會被依次執行並且彈出堆棧,直到回到全域的上下文。
執行內容:也稱為執行環節,一個執行的上下文可以抽象的理解為object。每一個執行的上下文都有一系列的屬性(我們稱為上下文狀態),他們用來追蹤關聯代碼的執行進度。主要有三個屬性:變數對象(variable object),this指標(this value),範圍鏈(scope chain)。
使用中的物件
當函數被調用者啟用,這個特殊的使用中的物件(activation object) 就被建立了。它包含普通參數(formal parameters) 與特殊參數(arguments)對象(具有索引屬性的參數映射表)。使用中的物件在函數上下文中作為變數對象使用。
即:函數的變數對象保持不變,但除去儲存變數與函式宣告之外,還包含以及特殊對象arguments 。
範圍鏈最佳化: 從範圍鏈的結構可以看出,在運行期內容相關的範圍鏈中,標識符所在的位置越深,讀寫速度就會越慢。因為全域變數總是存在於運行期上下文範圍鏈的最末端,因此在標識符解析的時候,尋找全域變數是最慢的。所以,在編寫代碼的時候應盡量少使用全域變數,儘可能使用局部變數。一個好的經驗法則是:如果一個跨範圍的對象被引用了一次以上,則先把它儲存到局部變數裡再使用。