摘要:正式由于作用域鏈的這種關系,我們就不難理解,為什么和不能通過作用域鏈向上搜索,因為對和的搜索在當前執行函數的活動對象就停止了。
對于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)
//偽代碼 //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)的內部對象
它定義了一個函數執行時的環境
函數每次執行時的執行環境獨一無二
多次調用函數就多次創建執行環境
并且函數執行完畢后,執行環境就會被銷毀
執行環境有自己的作用域鏈,用于解析標識符
所以當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...
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/81114.html
摘要:下面,讓我們以一個函數的創建和激活兩個時期來講解作用域鏈是如何創建和變化的。這時候執行上下文的作用域鏈,我們命名為至此,作用域鏈創建完畢。 JavaScript深入系列第五篇,講述作用鏈的創建過程,最后結合著變量對象,執行上下文棧,讓我們一起捋一捋函數創建和執行的過程中到底發生了什么? 前言 在《JavaScript深入之執行上下文棧》中講到,當JavaScript代碼執行一段可執行代...
摘要:開篇作用域是每種計算機語言最重要的基礎之一,因此要想深入的學習作用域和作用域鏈就是個繞不開的話題。這樣由多個執行上下文的變量對象構成的鏈表就叫做作用域鏈。這時候執行上下文的作用域鏈,我們命名為至此,作用域鏈創建完畢。 開篇 作用域是每種計算機語言最重要的基礎之一,因此要想深入的學習JavaScript,作用域和作用域鏈就是個繞不開的話題。 在《深入學習js之—-執行上下文棧》中我們提到...
摘要:每一個運行期上下文都和一個作用域鏈關聯。這個對象將被推入作用域鏈的頭部,這意味著函數的所有局部變量現在處于第二個作用域鏈對象中,因此訪問代價更高了。在代碼塊內部,函數的所有局部變量將會被放在第二個作用域鏈對象中。 參考: Javascript作用域原理 理解 JavaScript 作用域和作用域鏈 JavaScript 作用域 作用域就是變量與函數的可訪問范圍,即作用域控制著變量與函數...
摘要:變量對象作用域鏈因為變量對象在執行上下文進入執行階段時,就變成了活動對象,因此圖中使用了來表示。 作用域 作用域就是變量與函數的可訪問范圍,即作用域控制著變量與函數的可見性和生命周期。在 JavaScript 中,變量的作用域有全局作用域和局部作用域兩種。JavaScript 采用詞法作用域(lexical scoping),也就是靜態作用域。 靜態作用域 函數的作用域在函數定義的時候...
摘要:變量對象作用域鏈因為變量對象在執行上下文進入執行階段時,就變成了活動對象,因此圖中使用了來表示。 作用域 作用域就是變量與函數的可訪問范圍,即作用域控制著變量與函數的可見性和生命周期。在 JavaScript 中,變量的作用域有全局作用域和局部作用域兩種。JavaScript 采用詞法作用域(lexical scoping),也就是靜態作用域。 靜態作用域 函數的作用域在函數定義的時候...
閱讀 2609·2021-11-18 10:02
閱讀 2279·2021-09-30 09:47
閱讀 1745·2021-09-27 14:01
閱讀 3110·2021-08-16 11:00
閱讀 3163·2019-08-30 11:06
閱讀 2392·2019-08-29 17:29
閱讀 1533·2019-08-29 13:19
閱讀 445·2019-08-26 13:54