對於Javascript程序員來講,閉包總會讓你以爲既熟悉又陌生,然而它對於開發人員來講卻很是重要,javascript裏的許多設計模式中都用到了閉包,此處以函數做用域爲例。javascript
//示例代碼 var a=1; function foo(){ var b=2; console.log(a); function bar(){ var c=123; console.log(b); } bar(); } foo();
任何函數定義的時候,都會建立一個[[scope]]屬性,這個對象對應的是一個對象的列表,列表中的對象僅能javascript內部訪問,無法經過語法訪問,用代碼能夠表示爲:
1.函數定義時
在全局環境下定義了一個foo函數,此時foo函數的[[scope]]屬性中只包含一個全局對象GO(global object)html
//僞代碼 //js代碼默認進入全局執行環境,因此foo在初始時就被定義 foo.[[scope]]={ GO:{ this:window, window:{...}, document:{...}, a:undefined //此處是預編譯,因此a並無賦值 .... } } //當進入foo執行環境時,bar函數才被定義 bar.[[scope]]={ AO(foo):{ this:window, arguments:[], b:undefined }, GO:{ this:window, window:{...}, document:{...}, a:1 } }
2.函數被調用時
執行環境
在函數執行時,會建立一個叫作執行環境/執行上下文(execution context)的內部對象
它定義了一個函數執行時的環境
函數每次執行時的執行環境獨一無二
屢次調用函數就屢次建立執行環境
而且函數執行完畢後,執行環境就會被銷燬
執行環境有本身的做用域鏈,用於解析標識符java
因此當foo函數被調用的時候,會建立foo執行環境,每一個執行環境對應一個變量對象。首先會創一個它本身的活動對象【Activation Object】(這個對象中包含了this、參數(arguments)、局部變量(包括命名的參數)的定義,固然全局對象是沒有arguments的)和一個變量對象的做用域鏈[[scope chain]],而後,把這個執行環境的[[scope]]按順序複製到[[scope chain]]裏,最後把這個活動對象推入到[[scope chain]]的頂部。這樣[[scope chain]]就是一個有序的棧,這樣保了對執行環境有權訪問的全部變量和對象的有序訪問。程序員
//foo函數被調用時 foo.EC={ //foo的執行環境 AO:{ //foo的活動對象 this:window, arguments:[], b:undefined }, [[scope chain]]:{ AO:AO, //推入做用域鏈頂部的活動對象 GO:{...} //經過複製foo.[[scope]]獲得的全局對象 } ... } //函數的做用域鏈 foo.EC.[[scope chain]]={ AO:{ this:window, arguments:[], b:undefined }, GO:{ this:window, window:{...}, document:{...}, a:1 } }
//當bar函數被調用時 bar.EC={ AO:{ this:window, arguments:[], c:undefined }, [[scope chain]]:{ AO:AO //推入做用域鏈頂部的活動對象 AO:{...} //foo活動對象 GO:{...} //全局活動對象 } }
3.函數代碼執行階段
var b=2 實際上就是對做用域鏈AO對象中的b進行賦值,當執行console.log(a)時候,遇到標識符a,就會根據標識符的名稱在執行環境(Execution Context)的做用域鏈中進行搜索。從做用域鏈的第一個對象(該函數的Activation Object對象)開始,若是沒有找到,就搜索做用域鏈中的下一個對象,如此往復,直到找到了標識符的定義。若是在搜索完做用域中的最後一個對象,也就是全局對象(Global Object)之後也沒有找到,則會拋出一個錯誤,提示undefined。 設計模式
正式因爲做用域鏈的這種關係,咱們就不難理解,爲何this和arguments不能經過做用域鏈向上搜索,由於對this和arguments的搜索在當前執行函數的活動對象就中止了。閉包
以上是我的對於js做用域的理解, 若有錯誤歡迎討論,本文未涉及with等改變做用域的行爲
參考文章
http://www.cnblogs.com/pigtai...
http://blog.csdn.net/liujie19...
http://www.cnblogs.com/vadar/...
http://blog.csdn.net/q1056843...函數