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