天天看點

JAVASCRIPT之執行環境及作用域

執行環境(execution context, 為簡單起見,有時也稱為“環境”)是Javascript中最為重要的一個概念。

執行環境定義了變量或函數有權通路的其他資料,決定了它們各自的行為。每個執行環境都有一個與之相關聯的變量對象,環境中定義的所有變量和函數都儲存在這個對象中。雖然我們編寫的代碼無法通路這個對象,但解析器在處理資料時會在背景使用它。

全局執行環境是最外圍的一個執行環境。根據ECMAScript實作坐在的宿主環境不同,表示執行環境的對象也不一樣。在Web浏覽器中,全局執行環境被認為是window對象,是以所有全局變量和函數都是作為window對象的屬性和方法建立的。某個執行環境中所有代碼執行完畢後,該環境被銷毀,儲存在其中的所有變量和函數定義也随之銷毀(全局執行環境直到應用程式退出--例如關閉網頁或流浪器時才會被銷毀)。

每個函數都有自己的執行環境。當執行流進入一個函數時,函數的環境會就會被推入一個環境棧中。而在函數執行之後,棧将其環境彈出,把控制權傳回給之前的執行環境。ECMAScript程式中的執行流正是由這個友善的機制控制着。

當代碼在一個執行環境中執行時,會建立變量對象的一個作用域鍊(scope chain)。作用域鍊的用途,是保證對執行環境有權通路的所有變量和函數的有序通路。作用鍊的前端,始終都是目前執行的代碼所在的環境變量對象。如果這個環境是函數,則将其活動對象(activation object)作為變量對象。活動對象的下一個變量對象來自與包含(外部)環境,而再下一個變量對象則來自下一個包含環境。這樣一直延續到全局執行環境;全局執行環境的變量對象始終都是作用鍊中的最後一個對象。

辨別符解析是沿着作用域鍊一級一級地搜尋辨別符的過程。搜尋過程始終從作用鍊的前端開始,然後逐級地向後回溯,直至找到辨別符位置(如果找不到辨別符,通常會導緻錯誤發生)。

請看如下示例代碼:

var color = "blue";

function changeColor() {
    if (color === "blue") {
        color = "red";
    } else {
        color = "blue";
    }
}

changeColor();

console.log("Color is now " + color);      

在這個簡單的例子中,函數changeClor()的作用域鍊包含兩個對象:它自己的變量對象(其中定義這arguments對象)和全局環境的變臉對象。可以在函數内部通路變量color, 就是因為可以在這個作用域鍊中找到它。

此外,在局部作用域鍊中定義的變量可以在局部環境中與全局變量互換作用,如下面這個例子所示:

var color = "blue";

function changeColor() {
    var anotherColor = "red";
    function swapColors() {
        var tmpColor = anotherColor;
        anotherColor = color;
        color = tmpColor;
    }
    swapColors();
}

changeColor();      

以上代碼共涉及3個執行環境: 全局環境,changeColor()的局部環境和swapColor()的局部環境。全局環境中有一個變量color和一個函數changeColor()。changeColor()的局部環境中有一個名為anotherColor的變量和一個名為swapColors()的函數,但它可以也通路全局環境中的變量color。swapColors()的局部環境中有一個變量tempColor,該變量隻能在這個環境中通路到。無論全局環境還是changeColor()的局部環境都無權通路tempColor。然而,在swapColors()内部則可以通路其他兩個環境中的所有變量,因為那兩個環境是它的父執行環境。如下圖形象的展示了前面這個例子的作用域鍊。

JAVASCRIPT之執行環境及作用域

上圖中的矩形就表示特定的執行環境。其中,内部環境可以通過作用域鍊通路所有的外部環境,但外部環境不能通路内部環境中的任何變量和函數。這些環境之間的聯系是線性的,有次序的。每個環境都可以向上搜尋作用域鍊,以查詢變量和函數名;但任何環境都不能通過向下搜尋作用域鍊而進入另一個執行環境。對于這個例子中的swapColor而言,其作用域鍊中包含3個對象:swapColor()的變量對象,changeColor()的變量對象和全局變量對象。swapColors()的局部環境開始時會先在自己的變量對象中搜尋變量和函數名,如果搜尋不到則再搜尋上一級作用域鍊。changeColor()的作用域鍊中隻包含兩個對象,它自己的變量對象和全局變量對象。這也就是說,它不能通路swapColors()的環境。

備注: 摘取自《JAVASCRIPT進階程式設計:第3版》

繼續閱讀