理解做用域鏈

先來看兩個例子前端

var x = 10;

bar();   //10
function foo(){
  console.log(x);
}

function bar(){
  var x = 30;
  foo();
}

解析瀏覽器

執行bar,至關於執行foo(),foo裏面要輸出x,咱們首先要從foo本身的做用域下面去找
    foo裏邊是沒有聲明x的,而後咱們會到foo的詞法做用域去找,也就是聲明foo的做用域去找。
    在這裏foo的詞法做用域就是全局做用域,全局做用域裏聲明的x=10,因此輸出10
var x = 10;
    bar();  //30

    function bar(){
       var x = 30;
       function foo(){
           console.log(x); 
      }
       foo();
   }

解析函數

執行bar(),就會執行foo().foo裏輸出x,咱們首先找foo的做用域裏,發現沒有聲明x
    那就接着找foo的詞法做用域。也就是聲明foo的做用域,發現有x=30,因而輸出了30

幾個相關的概念

一 、execution context (執行上下文,也叫執行環境):code

  • 執行上下文定義了變量和函數有權訪問的其餘數據。對象

  • 每一個執行環境,都有一個與之關聯的變量對象(variable object).環境中定義的全部變量和函數都保存在這個對象中。(咱們編寫的代碼沒法訪問這個對象,可是解析器能夠)ci

  • 全局執行環境,是最外圍的一個執行環境,在WEB瀏覽器中,全局執行環境被認爲是 window對象,所以全部的全局變量和函數都是做爲window對象的屬性和方法建立的。作用域

  • 某個執行環境中的全部代碼都執行完畢以後,該環境被銷燬,保存在其中的全部變量和函數定義,也隨之銷燬。(全局執行環境,直到應用程序退出——例如關閉管業或瀏覽器時纔會被銷燬)it

  • 每一個函數都有本身的執行環境io

二 、scope chain(做用域鏈),activation object(活動對象)console

  • 當代碼在一個環境中執行時,會建立變量對象的一個做用域鏈。

  • 做用域鏈的前端,始終都是當前執行的代碼所在環境的變量對象。若是這個環境是函數,則將其活動對象做爲變量對象。活動對象在最開始只包含一個arguments對象(這個對象在全局執行環境中是不存在的)

  • 做用域鏈中的下一個變量對象來自包含(外部)環境,以此類推,一致延續到全局執行環境。

  • 全局執行環境的變量對象,始終都是做用域鏈中的最後一個對象。

三 、[[Scope]]屬性

  • 函數是特殊的可執行對象。
  • 既然是對象,就能夠擁有屬性。
  • 函數中存在着一個內部屬性[[Scope]](咱們不能使用,供JS引擎使用)
  • 函數被建立時,這個內部屬性就會包含函數被建立的做用域中對象的集合。
  • 這個集合呈鏈式鏈接,被稱爲函數的做用域鏈
  • 做用域鏈上的每個對象被稱爲變量對象(variable object)
  • 每個變量對象都以鍵值對形式存在

執行順序

//範例1
        var x = 10;

        bar();  //10
        function foo() {
            console.log(x);
        }

        function bar() {
            var x = 30;
            foo();

首先

1.代碼在一開始會有聲明前置,
      var x ;
      funciton bar();
      funciton foo();
      以後再去執行 x=10;

      在一開始的時候,這個執行環境叫全局執行環境(global Context),也就是全局做用域。

      全局執行環境裏包含了兩個對象,一個是活動對象(AO),一個是Scope屬性
      global Context = {
          AO : {
              x : 10;
              bar : function;
              foo : function;
           },
          Scope:null
       }

    聲明bar時  獲得下面:
    bar().[[Scope]]  = global Context.AO
    聲明foo時  獲得下面:
    foo().[[Scope]]  = global Context.AO
    
    執行代碼的時候,當咱們須要一個值,會首先從它的活動對象裏去找,若是找不到就要到它的[[Scope]] 裏去找。

   2.當調用bar()時,進入bar的執行上下文
    由於bar裏值聲明瞭一個x,因此bar的活動對象裏只有一個x
    barContext = {
      AO : {
          X : 30
      },
      Scope :bar.[[Scope]]   //global Context.AO
    }
    
   3. 當調用foo()的時候,進入foo的執行上下文
    fooContext = {
    //foo裏沒有聲明變量,foo也沒有參數,因此foo的活動對象是空的
    AO:{}
    Scope:foo.[[Scope]]    //global Context.AO
  }
相關文章
相關標籤/搜索