先來看兩個例子前端
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]]屬性
//範例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 }