摘要:正式由于作用域鏈的這種關(guān)系,我們就不難理解,為什么和不能通過作用域鏈向上搜索,因為對和的搜索在當(dāng)前執(zhí)行函數(shù)的活動對象就停止了。
對于Javascript程序員來說,閉包總會讓你覺得既熟悉又陌生,然而它對于開發(fā)人員來說卻非常重要,javascript里的許多設(shè)計模式中都用到了閉包,此處以函數(shù)作用域為例。
//示例代碼 var a=1; function foo(){ var b=2; console.log(a); function bar(){ var c=123; console.log(b); } bar(); } foo();
任何函數(shù)定義的時候,都會創(chuàng)建一個[[scope]]屬性,這個對象對應(yīng)的是一個對象的列表,列表中的對象僅能javascript內(nèi)部訪問,沒法通過語法訪問,用代碼可以表示為:
1.函數(shù)定義時
在全局環(huán)境下定義了一個foo函數(shù),此時foo函數(shù)的[[scope]]屬性中只包含一個全局對象GO(global object)
//偽代碼 //js代碼默認(rèn)進入全局執(zhí)行環(huán)境,所以foo在初始時就被定義 foo.[[scope]]={ GO:{ this:window, window:{...}, document:{...}, a:undefined //此處是預(yù)編譯,所以a并沒有賦值 .... } } //當(dāng)進入foo執(zhí)行環(huán)境時,bar函數(shù)才被定義 bar.[[scope]]={ AO(foo):{ this:window, arguments:[], b:undefined }, GO:{ this:window, window:{...}, document:{...}, a:1 } }
2.函數(shù)被調(diào)用時
執(zhí)行環(huán)境
在函數(shù)執(zhí)行時,會創(chuàng)建一個叫做執(zhí)行環(huán)境/執(zhí)行上下文(execution context)的內(nèi)部對象
它定義了一個函數(shù)執(zhí)行時的環(huán)境
函數(shù)每次執(zhí)行時的執(zhí)行環(huán)境獨一無二
多次調(diào)用函數(shù)就多次創(chuàng)建執(zhí)行環(huán)境
并且函數(shù)執(zhí)行完畢后,執(zhí)行環(huán)境就會被銷毀
執(zhí)行環(huán)境有自己的作用域鏈,用于解析標(biāo)識符
所以當(dāng)foo函數(shù)被調(diào)用的時候,會創(chuàng)建foo執(zhí)行環(huán)境,每個執(zhí)行環(huán)境對應(yīng)一個變量對象。首先會創(chuàng)一個它自己的活動對象【Activation Object】(這個對象中包含了this、參數(shù)(arguments)、局部變量(包括命名的參數(shù))的定義,當(dāng)然全局對象是沒有arguments的)和一個變量對象的作用域鏈[[scope chain]],然后,把這個執(zhí)行環(huán)境的[[scope]]按順序復(fù)制到[[scope chain]]里,最后把這個活動對象推入到[[scope chain]]的頂部。這樣[[scope chain]]就是一個有序的棧,這樣保了對執(zhí)行環(huán)境有權(quán)訪問的所有變量和對象的有序訪問。
//foo函數(shù)被調(diào)用時 foo.EC={ //foo的執(zhí)行環(huán)境 AO:{ //foo的活動對象 this:window, arguments:[], b:undefined }, [[scope chain]]:{ AO:AO, //推入作用域鏈頂部的活動對象 GO:{...} //通過復(fù)制foo.[[scope]]得到的全局對象 } ... } //函數(shù)的作用域鏈 foo.EC.[[scope chain]]={ AO:{ this:window, arguments:[], b:undefined }, GO:{ this:window, window:{...}, document:{...}, a:1 } }
//當(dāng)bar函數(shù)被調(diào)用時 bar.EC={ AO:{ this:window, arguments:[], c:undefined }, [[scope chain]]:{ AO:AO //推入作用域鏈頂部的活動對象 AO:{...} //foo活動對象 GO:{...} //全局活動對象 } }
3.函數(shù)代碼執(zhí)行階段
var b=2 實際上就是對作用域鏈AO對象中的b進行賦值,當(dāng)執(zhí)行console.log(a)時候,遇到標(biāo)識符a,就會根據(jù)標(biāo)識符的名稱在執(zhí)行環(huán)境(Execution Context)的作用域鏈中進行搜索。從作用域鏈的第一個對象(該函數(shù)的Activation Object對象)開始,如果沒有找到,就搜索作用域鏈中的下一個對象,如此往復(fù),直到找到了標(biāo)識符的定義。如果在搜索完作用域中的最后一個對象,也就是全局對象(Global Object)以后也沒有找到,則會拋出一個錯誤,提示undefined。
正式由于作用域鏈的這種關(guān)系,我們就不難理解,為什么this和arguments不能通過作用域鏈向上搜索,因為對this和arguments的搜索在當(dāng)前執(zhí)行函數(shù)的活動對象就停止了。
以上是個人對于js作用域的理解, 如有錯誤歡迎討論,本文未涉及with等改變作用域的行為
參考文章
http://www.cnblogs.com/pigtai...
http://blog.csdn.net/liujie19...
http://www.cnblogs.com/vadar/...
http://blog.csdn.net/q1056843...
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/81114.html
摘要:下面,讓我們以一個函數(shù)的創(chuàng)建和激活兩個時期來講解作用域鏈?zhǔn)侨绾蝿?chuàng)建和變化的。這時候執(zhí)行上下文的作用域鏈,我們命名為至此,作用域鏈創(chuàng)建完畢。 JavaScript深入系列第五篇,講述作用鏈的創(chuàng)建過程,最后結(jié)合著變量對象,執(zhí)行上下文棧,讓我們一起捋一捋函數(shù)創(chuàng)建和執(zhí)行的過程中到底發(fā)生了什么? 前言 在《JavaScript深入之執(zhí)行上下文?!分兄v到,當(dāng)JavaScript代碼執(zhí)行一段可執(zhí)行代...
摘要:開篇作用域是每種計算機語言最重要的基礎(chǔ)之一,因此要想深入的學(xué)習(xí)作用域和作用域鏈就是個繞不開的話題。這樣由多個執(zhí)行上下文的變量對象構(gòu)成的鏈表就叫做作用域鏈。這時候執(zhí)行上下文的作用域鏈,我們命名為至此,作用域鏈創(chuàng)建完畢。 開篇 作用域是每種計算機語言最重要的基礎(chǔ)之一,因此要想深入的學(xué)習(xí)JavaScript,作用域和作用域鏈就是個繞不開的話題。 在《深入學(xué)習(xí)js之—-執(zhí)行上下文棧》中我們提到...
摘要:每一個運行期上下文都和一個作用域鏈關(guān)聯(lián)。這個對象將被推入作用域鏈的頭部,這意味著函數(shù)的所有局部變量現(xiàn)在處于第二個作用域鏈對象中,因此訪問代價更高了。在代碼塊內(nèi)部,函數(shù)的所有局部變量將會被放在第二個作用域鏈對象中。 參考: Javascript作用域原理 理解 JavaScript 作用域和作用域鏈 JavaScript 作用域 作用域就是變量與函數(shù)的可訪問范圍,即作用域控制著變量與函數(shù)...
摘要:變量對象作用域鏈因為變量對象在執(zhí)行上下文進入執(zhí)行階段時,就變成了活動對象,因此圖中使用了來表示。 作用域 作用域就是變量與函數(shù)的可訪問范圍,即作用域控制著變量與函數(shù)的可見性和生命周期。在 JavaScript 中,變量的作用域有全局作用域和局部作用域兩種。JavaScript 采用詞法作用域(lexical scoping),也就是靜態(tài)作用域。 靜態(tài)作用域 函數(shù)的作用域在函數(shù)定義的時候...
閱讀 2638·2021-11-18 10:02
閱讀 2289·2021-09-30 09:47
閱讀 1808·2021-09-27 14:01
閱讀 3120·2021-08-16 11:00
閱讀 3172·2019-08-30 11:06
閱讀 2403·2019-08-29 17:29
閱讀 1543·2019-08-29 13:19
閱讀 453·2019-08-26 13:54