JS進階之---執行上下文,變量對象,變量提高

 

1、結構順序大致介紹web

  JavaScript代碼的整個執行過程,分爲兩個階段,代碼編譯階段與代碼執行階段。瀏覽器

    編譯階段由編譯器完成,將代碼翻譯成可執行代碼,這個階段做用域規則會肯定。函數

    執行階段由引擎完成,主要任務是執行可執行代碼,執行上下文在這個階段建立。執行上下文也分爲建立階段和執行階段。
this

      1.首先進入全局環境,建立一個全局執行上下文,全局變量對象window,全局做用域Global,肯定this指向,this==window。spa

      2.在執行階段,會完成變量賦值,函數引用,以及執行其餘代碼等。瀏覽器的斷點調試只能用於執行階段。線程

      3.在執行階段,若是遇到函數引用,會進入函數環境,建立一個執行上下文。而在這個執行上下文中,也分爲建立階段和執行階段。接下來咱們主要討論函數環境的建立階段和執行階段,不考慮全局環境,由於全局環境也能夠理解爲在一個大的函數環境中。行爲基本一致。翻譯

 

 

2、執行上下文調試

  每次當Js引擎轉到可執行代碼的時候,就會進入一個執行上下文。執行上下文能夠理解爲當前代碼的執行環境,它會造成一個做用域。JavaScript中的運行環境大概包括三種狀況。code

  • 全局環境:JavaScript代碼運行起來會首先進入該環境
  • 函數環境:當函數被調用執行時,會進入當前函數中執行代碼
  • eval

  當代碼在執行過程當中,遇到以上三種狀況,都會生成一個執行上下文,放入棧中,咱們稱其爲函數調用棧(call stack)。棧底永遠都是全局上下文,而棧頂就是當前正在執行的上下文。處於棧頂的上下文執行完畢以後,就會自動出棧。對象

  注意:函數中,遇到return能直接終止可執行代碼的執行,所以會直接將當前上下文彈出棧。

  執行上下文特色:

    • 單線程
    • 同步執行,只有棧頂的上下文處於執行中,其餘上下文須要等待
    • 全局上下文只有惟一的一個,它在瀏覽器關閉時出棧
    • 函數的執行上下文的個數沒有限制
    • 每次某個函數被調用,就會有個新的執行上下文爲其建立,即便是調用的自身函數,也是如此。
 

  當調用一個函數時,一個新的執行上下文就會被建立。而一個執行上下文的生命週期能夠分爲兩個階段。
    建立階段
:在這個階段中,執行上下文會分別建立變量對象,創建做用域鏈,以及肯定this的指向。
    代碼執行:階段
建立完成以後,就會開始執行代碼,這個時候,會完成變量賦值,函數引用,以及執行其餘代碼。

      

    

 

3、變量對象

  在執行上下文的建立階段,會進行變量對象的建立。

    而變量對象的建立過程又分爲:
      1.參數對象建立。創建arguments對象,檢查當前上下文中的參數,創建該對象下的屬性與屬性值。

      2.函數聲明。檢查當前上下文的函數聲明,也就是使用function關鍵字聲明的函數。在變量對象中以函數名創建一個屬性,屬性值爲指向該函數所在內存地址的引用。若是函數名的屬性已經存在,那麼該屬性將會被新的引用所覆蓋。
function聲明會比var聲明優先級更高一點。
      3.變量聲明。檢查當前上下文中的變量聲明,每找到一個變量聲明,就在變量對象中以變量名創建一個屬性,屬性值爲undefined。若是該變量名的屬性已經存在,爲了防止同名的函數被修改成undefined,則會直接跳過,原屬性值不會被修改。

 

  在執行上下文的執行階段,進行變量對象的賦值,函數的引用等。

    進入執行階段以前,變量對象中的屬性都不能訪問!可是進入執行階段以後,變量對象轉變爲了活動對象,裏面的屬性都能被訪問了,而後開始進行執行階段的操做。

    變量對象和活動對象其實都是同一個對象,只是處於執行上下文的不一樣生命週期。

 

 

4、舉個例子: 

function test() {
    var a = 1;
    function foo() {
        return 2;
    }
}

test();

  咱們直接從test()的執行上下文開始理解。全局做用域中運行test()時,test()的執行上下文開始建立。爲了便於理解,咱們用以下的形式來表示。 

  建立階段:

testEC = {
    // 變量對象  VO: {},  scopeChain: {},  this: {} } // 由於本文暫時不詳細解釋做用域鏈和this,因此把變量對象專門提出來講明 // VO 爲 Variable Object的縮寫,即變量對象 VO = {  arguments: {...}, //參數對象。注:在瀏覽器的展現中,函數的參數可能並非放在arguments對象中,這裏爲了方便理解,我作了這樣的處理  foo: <foo reference> // 表示foo的地址引用  a: undefined }

  執行階段:

VO -> AO // Active Object 即活動對象 AO = { arguments: {...}, foo: <foo reference>, a: 1 }

 

 

5、變量提高

  變量提高是將變量聲明提高到它所在做用域的最開始的部分。如:

console.log(a);  //undefined
console.log(b); //Uncaught ReferenceError: b is not defined
var a = 1;

  代碼執行分爲建立和執行兩個階段,代碼開始執行的時候,建立階段已經完成,因此變量對象已經建立完成。此時a是undefined,而b是沒有的。

  因此也就解釋了變量提高的現象,由於在執行的時候,全部的變量對象早已建立完成,只是尚未被賦值。

相關文章
相關標籤/搜索