深入理解Javascript--作用域和賦值操作
作用域作為一個(gè)最基礎(chǔ)的功能存在于各種編程語(yǔ)言中,它使得我們的編程更加靈活有趣。其基礎(chǔ)功能就是存儲(chǔ)變量中的值,然后可以對(duì)值進(jìn)行訪問(wèn)和修改。
可能我們都知道作用域的一些概念,以及其一些擴(kuò)展的一些內(nèi)容閉包等,但是相對(duì)于這些可能我們?nèi)チ私膺@些變量到底是存到了哪里,而我們的程序是如何訪問(wèn)到他們的會(huì)更加有趣。
var a = 1;
首先我們要了解到在我們進(jìn)行聲明變量并進(jìn)行賦值的時(shí)候到底誰(shuí)參與了我們的整個(gè)流程。
1,引擎:它參與了整個(gè)JS程序的編譯和執(zhí)行。
2,編譯器:它負(fù)責(zé)了語(yǔ)法分析和代碼的生成。
3,作用域:它負(fù)責(zé)手機(jī)并維護(hù)所有的標(biāo)識(shí)符也就(變量)組成的一系列查詢(xún),并對(duì)此實(shí)施了一套十分嚴(yán)格的規(guī)則,確定當(dāng)前執(zhí)行的代碼對(duì)這些標(biāo)識(shí)符的訪問(wèn)權(quán)限。
當(dāng)引擎看到var a =1;的時(shí)候它和我們所想的是不一樣的,我們想這是一個(gè)聲明,他所認(rèn)為的其實(shí)是這里有倆完全不同的聲明,一個(gè)由編譯器在編譯的時(shí)候處理,另一個(gè)則由引擎在運(yùn)行時(shí)候處理。那我們看看他們到底是怎么工作的。
編譯器會(huì)先講var a = 1;這段程序分解成詞法單元,然后將詞法單元解析成一個(gè)樹(shù)結(jié)構(gòu),但是當(dāng)編譯器開(kāi)始進(jìn)行代碼生成的時(shí)候,他對(duì)這段程序的處理方式會(huì)有所不同。
在我們理解的范圍內(nèi),編譯器是這樣工作的:為一個(gè)變量分配內(nèi)存,將其命名為a,然后講值1保存進(jìn)這個(gè)變量,但事實(shí)是不同的。
1,遇到 var a 的時(shí)候,編譯器會(huì)先詢(xún)問(wèn)作用域是否已經(jīng)有一個(gè)該名稱(chēng)的變量存在于同一個(gè)作用域的集合中。如果是,編譯器就會(huì)忽略該聲明并繼續(xù)進(jìn)行編譯,不然的話他會(huì)要求作用域在當(dāng)前作用域的集合中聲明一個(gè)變量命名為a。
2,然后編譯器開(kāi)始為引擎生成運(yùn)行所需的代碼,這些代碼會(huì)被用來(lái)處理 a = 1 這個(gè)賦值的操作。然后引擎運(yùn)行,它會(huì)先詢(xún)問(wèn)作用域,當(dāng)前作用域集合中是否存在了一個(gè)叫a的變量,如果是引擎就會(huì)使用這個(gè)變量,如果否,引擎會(huì)繼續(xù)在當(dāng)前作用域的上級(jí)作用域查找該變量。最后只要找到了a,引擎就會(huì)把1賦值給它,如果沒(méi)有找到,引擎就會(huì)拋出一個(gè)異常。
所以說(shuō):在新變量的賦值中存在兩個(gè)操作,第一個(gè)是編譯器聲明變量,第二個(gè)就是引擎在作用域中查找該變量,并對(duì)其賦值。
下面看一段簡(jiǎn)單的代碼
function demo(a){console.log(a) }demo(2);
在繼續(xù)說(shuō)之前,我們先看看LHS和RHS,顧名思義,一個(gè)左一個(gè)右。這是引擎對(duì)變量所用的兩個(gè)查詢(xún),L和R代表的是一個(gè)賦值的左側(cè)和右側(cè)(大部分情況下),也就是說(shuō)當(dāng)變量出現(xiàn)在賦值的左側(cè)時(shí)進(jìn)行LHS查詢(xún),出現(xiàn)在右側(cè)時(shí)進(jìn)行RHS查詢(xún)。但是更確切的說(shuō)法其實(shí)是RHS查詢(xún)只是簡(jiǎn)單的查找某個(gè)變量的值,而LHS查詢(xún)則是找到變量的容器本身,從而對(duì)其進(jìn)行賦值操作。那么根據(jù)這個(gè)說(shuō)法,我們可以發(fā)現(xiàn)RHS其實(shí)代表的應(yīng)該是“非左側(cè)”。我們看一個(gè)簡(jiǎn)單代碼。
var a = 1; console.log(a);
在上面的代碼中,var a =1;對(duì)a的引用是一個(gè)LHS引用,而console.log(a)的a其實(shí)就是一個(gè)RHS引用。再看一個(gè)例子:
function demo(a){console.log(a); }demo(1);
上面的代碼中其實(shí)包含了RHS和LHS引用。我們理解下demo(1);的意思,它其實(shí)意味著RHS引用demo這個(gè)值,(...)意味著它需要被執(zhí)行,而在執(zhí)行的過(guò)程中,有一個(gè)隱式的LRS引用 a = 1; 這個(gè)查詢(xún)發(fā)生在參數(shù)傳遞的過(guò)程中。其中的console.log(a)也是個(gè)RHS引用。
同時(shí)我們需要知道,不成功的RHS會(huì)導(dǎo)致拋出一個(gè)異常,而不成功的LHS引用會(huì)導(dǎo)致自動(dòng)隱式的創(chuàng)建一個(gè)全局變量(非嚴(yán)格模式),或者拋出異常(嚴(yán)格模式)。
作用域的嵌套當(dāng)一個(gè)塊或者函數(shù)嵌套在另一個(gè)塊或者函數(shù)內(nèi)時(shí),就發(fā)生了作用域的嵌套。因此,當(dāng)在當(dāng)前作用域中無(wú)法找到該變量時(shí),引擎就會(huì)在外層嵌套的作用域中繼續(xù)查找(若一直沒(méi)有找到會(huì)到達(dá)全局作用域),直到找到該變量。
上圖一層一層往外形成的結(jié)構(gòu)就是我們常說(shuō)的作用域鏈,最內(nèi)層代表當(dāng)前執(zhí)行環(huán)境的作用域,最外層代表全局作用域。LHS和RHS都會(huì)在當(dāng)前作用域進(jìn)行查找,如果沒(méi)有找到,就會(huì)向外,以此類(lèi)推,如果到達(dá)全局作用域都沒(méi)有找到,那無(wú)論如何這個(gè)查找過(guò)程都會(huì)停止。
來(lái)自:http://www.cnblogs.com/xiaoloulan/p/5961528.html
相關(guān)文章:
1. Python如何批量生成和調(diào)用變量2. ASP.NET MVC實(shí)現(xiàn)橫向展示購(gòu)物車(chē)3. ASP.Net Core對(duì)USB攝像頭進(jìn)行截圖4. .net如何優(yōu)雅的使用EFCore實(shí)例詳解5. ASP.Net Core(C#)創(chuàng)建Web站點(diǎn)的實(shí)現(xiàn)6. python 爬取京東指定商品評(píng)論并進(jìn)行情感分析7. python基礎(chǔ)之匿名函數(shù)詳解8. Python獲取B站粉絲數(shù)的示例代碼9. ajax動(dòng)態(tài)加載json數(shù)據(jù)并詳細(xì)解析10. 通過(guò)CSS數(shù)學(xué)函數(shù)實(shí)現(xiàn)動(dòng)畫(huà)特效
