變量對象和執行環境的理解

背景

夯實基礎纔是進步的根源,基礎不牢地動山搖!!因而乎,結合《javascript高級程序設計》來點基礎的學習和理解。本文主要會有兩部分。rt!!javascript

正文

一、執行環境的理解java

執行環境(或者執行上下文)(execution context 後面簡稱ec)定義了變量或者函數有權訪問的其餘數據,決定了他們各自的行爲。若是很差理解的話,接着看後面。web

全局執行環境是最外圍的一個執行環境,在web瀏覽器中,全局執行環境被默認爲是指window對象。所以全部的全局變量和函數都是做爲window對象的屬性和方法建立的。全局執行環境直到應用程序推出纔會被銷燬(例如關閉網頁或者瀏覽器的時候)。瀏覽器

每一個函數都有本身的執行環境。當執行流進入一個函數的時候,函數的環境就會被推入一個環境棧中,而在函數執行以後,棧將其環境彈出。把控制權返回給以前的執行環境了。函數

執行環境通常分爲全局執行環境和函數執行環境。學習

這個時候應該上代碼了(高程上的代碼)this

var color = 'blue';

function changeColor() {
    var anotherColor = 'red';

    function swapColors() {
        var tempColor = anotherColor;
        anotherColor = color;
        color = tempColor;
    }

    swapColors();
}

changeColor();

來看看流程吧:spa

  1. 全局環境入棧
    image線程

  2. 全局環境入棧以後,其中的可執行代碼開始執行,直到遇到了changeColor(),這一句激活函數changeColor建立它本身的執行上下文,所以第二步就是changeColor的執行上下文入棧。
    image設計

  3. changeColor的環境入棧以後,js執行引擎開始執行其中的可執行代碼,遇到swapColors()以後又激活了一個執行上下文。所以第三步是swapColors的執行上下文入棧。
    wechatimg1

  4. 在swapColors的可執行代碼中,再沒有遇到其餘能生成執行環境的狀況,因此在swapColors順利執行完畢後,swapColors的環境從棧中彈出

  5. swapColors環境彈出後繼續changeColor的執行,發現沒有能夠執行的了。而後就彈出。

  6. 最後只剩下全局環境了。這個是要只有關閉當前網頁或者瀏覽器就能銷燬該環境。

總結

  1. 全部變量都存在於一個執行環境中。

  2. 全局環境只能訪問全局環境中的變量和函數,不能訪問局部環境中的任何數據。

  3. 執行環境有全局執行環境和函數執行環境之分。

  4. js單線程,是同步執行的,只有棧頂的環境處於執行中,其餘環境須要等待。

二、變量對象的理解

上面咱們講到了執行環境,環境中的變量和函數都是保存在什麼地方的呢?

好了,不賣關子了。每一個執行環境都有一個與該環境相關聯的變量對象(variable object)。環境中定義的全部變量和函數都是保存在這個對象中的。雖然咱們編寫的代碼沒有辦法直接訪問這個對象,可是js解析器在處理數據的時候會使用它。

執行環境的生命週期:
wechatimg15
變量對象的建立
image
上面就是變量對象的一個建立過程,這個過程的解釋:

  1. 創建arguments對象。檢查當前上下文中的參數,創建該對象下的屬性與屬性值。

  2. 檢查當前上下文的函數聲明,也就是使用function關鍵字聲明的函數。在變量對象中以函數名創建一個屬性,屬性值爲指向該函數所在內存地址的引用。若是函數名的屬性已經存在,那麼該屬性將會被新的引用所覆蓋。

  3. 檢查當前上下文中的變量聲明,每找到一個變量聲明,就在變量對象中以變量名創建一個屬性,屬性值爲undefined。若是該變量名的屬性已經存在,爲了防止同名的函數被修改成undefined,則會直接跳過,原屬性值不會被修改。

上面的代碼解釋:

function test(c, d) {
    console.log(d);
    console.log(a);
    console.log(bar());
    console.log(c);
    
    var a = 1;
    function bar() {
        return 2;
    }
}

test(3,4);


//建立過程  EC = execution context
testEC = {
    // 變量對象
    VO: {},
    // 做用於鏈
    scopeChain: {},
    // 肯定this指向
    this: {}
}

// VO = Variable Object,即變量對象
VO = {
    arguments: {
        c: undefined,
        d: undefined
    },  //注:在瀏覽器的展現中,函數的參數可能並非放在arguments對象中,這裏爲了方便理解,我作了這樣的處理
    bar: <bar reference>  // 表示foo的地址引用
    a: undefined
}

// 執行階段
VO ->  AO   // Active Object
AO = {
    arguments: {
        c: 3,
        d: 4
    },
    bar: <bar reference>,
    a: 1
}


// 實際執行
function test(c, d) {
    // arguments = { c : 3, d : 4 }; // 這樣理解方便點,理解arguments對象
    function foo() {
        return 2;
    }
    var a;
    console.log(a);
    console.log(foo());
    a = 1;
}

test(3, 4);

就是在執行環境在建立階段的時候全部的變量是不能被訪問的,只有在執行階段的時候才能被訪問,由於此時的變量對象被轉換成了活動對象。

// 執行階段
VO ->  AO   // Active Object
AO = {
    arguments: {...},
    foo: <foo reference>,
    a: 1
}

說到底變量對象和活動對象本質上是同樣的,只是處於執行環境的不一樣生命期。

最後全局環境的變量對象

windowEC = {
    VO: window,
    scopeChain: {},
    this: window
}

總結

  1. 活動對象和變量對象是執行環境在不一樣生命期的不一樣叫法。

  2. function聲明會比var聲明優先級更高一點。

  3. 未進入執行階段以前,變量對象中的屬性都不能訪問。

感謝

《javascript高級程序設計》
知乎上面的答案
波同窗變量對象詳解

相關文章
相關標籤/搜索