執行環境是JavaScrpt 最重要的概念之一,執行環境定義了變數或函數有權訪問的其它數據,決定了它們各自的行為。每個執行環境都有一個與之關聯的變數對象,或者說一個執行環境就是一個對象。環境中定義的所有變數和函數都保存在這個對象中。雖然我們編寫的代碼無法訪問這個對象,但解析器在處理數據時會在後臺使用 ...
執行環境是JavaScrpt 最重要的概念之一,執行環境定義了變數或函數有權訪問的其它數據,決定了它們各自的行為。每個執行環境都有一個與之關聯的變數對象,或者說一個執行環境就是一個對象。環境中定義的所有變數和函數都保存在這個對象中。雖然我們編寫的代碼無法訪問這個對象,但解析器在處理數據時會在後臺使用它。
全局執行環境是最外圍的一個執行環境。在Web瀏覽器中,全局執行環境被認為是window 對象,因此所有全局變數和函數都是作為window對象的屬性和方法創建的。某個執行環境中的所有代碼執行完畢後,該環境被銷毀,保存在其中的所有變數和函數定義也隨之銷毀,全局執行環境直到應用程式退出才被銷毀,關閉網頁或瀏覽器。
每個函數都有自己的執行環境。當執行流進入一個函數時,函數的環境就會被推入一個環境棧中。而在函數執行後,棧將環境彈出,把控制權返回給之前的執行環境。
當代碼在一個環境中執行時,會創建變數對象的一個作用域鏈。作用域鏈的用途,是保證對執行環境有權訪問的所有變數和函數的有序訪問。作用域鏈的前端,始終都是當前執行的代碼所在環境的變數對象。如果這個環境是函數,則將其活動對象作為變數對象,活動對象最開始只包含一個變數,即arguments對象。作用域鏈中的下一個變數對象來自包含環境,再下一個變數對象則來自下一個包含環境。這樣一直延續到全局執行環境;全局執行環境的變數對象始終都是作用域鏈中的最後一個對象。
標識符解析是沿著作用域鏈一級一級地搜索標識符的過程。搜索過程始終從作用域鏈的前端開始,然後逐級地向後回溯,直到找到標識符為止,如果找不到標識符,通常會導致錯誤發生。
請看下麵代碼:
var color = “blue”
function changeColor(){
if (color == "blue"){
color = "red";
}else {
color = "blue";
}
}
changeColor();
alert ( "Color is now " + color);
這個簡單的例子中,函數changeColor() 的作用域鏈包含兩個對象:它自己的變數對象(其中有arguments對象),和全局環境的變數對象。可以在函數內部訪問color, 就是因為可以在這個作用域鏈中找到它。
此外,在局部作用域中定義的變數可以在局部環境中與全局變數互換使用,如下麵這個例子:
var color = “blue”
function changeColor(){
var anotherColor = "red";
function swapColors(){
var tempColor = anotherColor;
anotherColor = color;
color = tempColor;
// 這裡可以訪問 color ,anotherColor ,tempColor
}
// 這裡可以訪問 color ,anotherColor ,但不能訪問 tempColor
swapColors();
}
// 這裡只能訪問 color
changeColor();
以上代碼共涉及3個執行環境:全局環境,changeColor()的局部環境和swapColors()的局部環境,全局環境中有一個變數color和一個函數changeColor(). changeColor()的局部環境中有一個名為anotherColor的變數和一個名為swapColors()的函數,但它也可以訪問全局環境中的變數color. swapColors()的局部變數中有一個變數tempColor,該變數只能在這個環境中訪問到。無論全局環境還是changeColor()的局部環境都無權訪問tempColor. 然而,在swapColors()內部則可以訪問其它兩個環境中的所有變數,因為那兩個環境是它的父執行環境。下圖形象地展示了前面這個例子的作用域鏈。
圖中矩形表示特定的執行環境,其中,內部環境可以通過作用域鏈訪問所有的外部環境,但外部環境不能訪問內部環境中的任何變數和函數。這些環境之間的聯繫是線性,有次序的。每個環境都可以向上搜索作用域鏈,以查詢變數和函數名;但任何環境都不能通過向下搜素所用域鏈而進入另一個執行環境。對於這個例子中的swapColors()而言,其作用域鏈中包含3個對象;swapColors()的變數對象,changeColor()的變數對象和全局變數對象。swapColors()的局部環境開始時會先在自己的變數對象中搜索變數和函數名,如果搜索不到則再搜索上一級作用域鏈。changeColor()的作用域鏈中只包含兩個對象:它自己的變數對象和全局變數對象。這也就是說,它不能訪問swapColors()的環境。