淺談javascript函數執行過程

javascript函數執行過程:javascript

  1. 爲函數建立一個執行環境前端

  2. 複製函數的 [[scopes]] 屬性中的對象構建起執行環境的做用鏈域java

  3. 建立函數活動對象並推入執行環境做用鏈域的前端閉包

  4. 執行代碼函數

  5. 銷燬執行環境和活動對象(閉包狀況下活動對象仍被引用沒被銷燬)this

 

用例子來講明:spa

function Person(name) {
    this.getName = function() {
        return name;
    };

    this.setName = function(value) {
        name = value;
    };
}

var person = new Person("Candy");
alert(person.getName()); //"Candy"
person.setName("Greg");
alert(person.getName()); //"Greg"

 

以調用Person()構造函數、setName() 函數爲例,函數執行過程當中,各對象的關係以下:對象

(1)未調用前,只存在全局變量對象blog

  全局變量中定義了Person() 構造函數,Person做爲全局變量對象的一個屬性,[[scopes]] 保存着Person() 構造函數的做用鏈域,由於Person() 構造函數是定義在全局變量對象裏面的ip

  Person爲何會有 [[scopes]] 屬性???

  在建立函數時,會建立一個預先包含全局變量對象的做用鏈域,這個做用鏈域被保存在內部的 [[scopes]] 屬性中

(2)new Person() 建立對象,調用以後,存在全局變量對象,Person對象

  用new調用構造函數會通過如下4個步驟:

    1. 建立一個新對象

    2. 將構造函數的做用域賦給新對象(所以this就指向這個新對象——person,這也是變量name爲何不是對象屬性的緣由)

    3. 執行構造函數中的代碼(爲新對象添加屬性)

    4. 返回新對象

  重點說第3個過程,執行過程如圖:

調用(執行)函數時,會爲函數建立一個執行環境,而後經過複製函數的 [[scopes]] 屬性中的對象構建起執行環境的做用鏈域。此後,又有一個活動對象(Person的活動對象)被建立並推入執行環境做用鏈域的前端,因此圖中的做用鏈域有2層。

  調用完畢後,返回Person對象

Person執行環境在函數執行完畢後銷燬,Person活動對象沒有被銷燬

  爲何Person活動對象沒有被銷燬???

    這種狀況屬於閉包:Person活動對象仍然被getName、setName的 [[scopes]] 引用,即仍在做用鏈域中,因此沒有被銷燬

  注意:

    Person() 構造函數中定義了getName()、setName() 兩個函數,還有函數的參數name

    new Person() 建立的 Person對象 的屬性只有getName()、setName(),沒有name屬性,name不是用this聲明的,不是Person對象的屬性

     

(3)調用setName(),存在全局變量對象,Person對象

 

 建立setName() 的執行環境,而後經過複製函數的 [[scopes]] 屬性中的對象構建起執行環境的做用鏈域。此後,又有一個活動對象(setName的活動對象)被建立並推入執行環境做用鏈域的前端,因此圖中的做用鏈域有3層。

 函數執行完畢後:

 

 

setName執行環境和setName活動對象都被銷燬,由於setName活動對象沒有被引用

 

- 其餘:

經過這個例子,也很好理解爲何person.name是undefined,由於person對象沒有name這個屬性,getName、setName能訪問name屬性是由於它們經過做用鏈域訪問到了Person活動對象中的name屬性

 

PS:用構造函數建立的對象是獨立的

相關文章
相關標籤/搜索