javascript
LHS 和 RHS---你所不知道的JavaScript
目錄
1、LHS(Left Hand Side)和?RHS(Right Hand Side)
2、實(shí)例詳解
3、總結(jié)
變量的賦值操作會(huì)執(zhí)行兩個(gè)動(dòng)作, 首先編譯器會(huì)在當(dāng)前作用域中聲明一個(gè)變量(如果之前沒(méi)有聲明過(guò)), 然后在運(yùn)行時(shí)引擎會(huì)在作用域中查找該變量, 如果能夠找到就會(huì)對(duì)它賦值。----《你所不知道的JavaScript(上)》?P7
而要講的 LHS 和 RHS 就是上面說(shuō)的對(duì)變量的兩種查找操作,查找的過(guò)程是由作用域(詞法作用域)進(jìn)行協(xié)助,但是引擎執(zhí)行怎樣的查找, 會(huì)影響最終的查找結(jié)果。?
?
1、LHS(Left Hand Side)和?RHS(Right Hand Side)
當(dāng)變量出現(xiàn)在賦值操作的左側(cè)時(shí)進(jìn)行 LHS 查詢(xún), 出現(xiàn)在右側(cè)時(shí)進(jìn)行 RHS 查詢(xún)。講得更準(zhǔn)確一點(diǎn), RHS 查詢(xún)與簡(jiǎn)單地查找某個(gè)變量的值別無(wú)二致, 而 LHS 查詢(xún)則是試圖找到變量的容器本身, 從而可以對(duì)其賦值。 從這個(gè)角度說(shuō), RHS 并不是真正意義上的“賦值操作的右側(cè)”, 更準(zhǔn)確地說(shuō)是“非左側(cè)”。? ----《你所不知道的JavaScript(上)》?P7
簡(jiǎn)單來(lái)說(shuō),
(1)LHS查詢(xún)指的是找到變量的容器本身,從而可以對(duì)其進(jìn)行賦值。也就是找到賦值操作的目標(biāo)。LHS查詢(xún)的時(shí)候會(huì)沿著作用域鏈進(jìn)行查詢(xún),找到的話就會(huì)將值賦值給這個(gè)變量,如果到達(dá)作用域頂端仍然找不到,就會(huì)在作用域鏈頂端創(chuàng)建這個(gè)變量(在嚴(yán)格模式中?LHS?查詢(xún)失敗時(shí), 并不會(huì)創(chuàng)建并返回一個(gè)全局變量, 引擎會(huì)拋出同?RHS?查詢(xún)失敗時(shí)類(lèi)似的?ReferenceError?異常)?。
var a = 2;這里對(duì)?a?的引用則是?LHS?引用, 因?yàn)閷?shí)際上我們并不關(guān)心當(dāng)前a的值是什么, 只是想要為?=2?這個(gè)賦值操作找到一個(gè)目標(biāo)。
(2)RHS查詢(xún)就是普通的查詢(xún)變量的值,即獲取變量的值。RHS查詢(xún)的時(shí)候會(huì)沿著作用域鏈進(jìn)行查詢(xún),找到的話就會(huì)取得這個(gè)值并返回,如果到達(dá)作用域頂端仍然找不到,引擎就會(huì)拋出?ReferenceError異常。如果?RHS?查詢(xún)找到了一個(gè)變量, 但是你嘗試對(duì)這個(gè)變量的值進(jìn)行不合理的操作,比如試圖對(duì)一個(gè)非函數(shù)類(lèi)型的值進(jìn)行函數(shù)調(diào)用, 或著引用?null?或?undefined?類(lèi)型的值中屬性, 那么引擎會(huì)拋出另外一種類(lèi)型的異常, 叫作?TypeError。
(注:ReferenceError?同作用域判別失敗相關(guān), 而?TypeError?則代表作用域判別成功了, 但是對(duì)結(jié)果的操作是非法或不合理的。)
舉個(gè)栗子:
console.log(a);這里的a就是一個(gè)RHS引用,因?yàn)閏onsole.log需要獲取到a的值才能輸出a的值。當(dāng)然這里的console.log也是一個(gè)RHS引用,這里對(duì)console 對(duì)象進(jìn)行RHS 查詢(xún),并且檢查得到的值中是否有一個(gè)叫作log 的方法。例子中的a因?yàn)闆](méi)有聲明過(guò),所以會(huì)拋出錯(cuò)誤。如下圖所示:
?
2、實(shí)例詳解
實(shí)例1:
function foo(a) {console.log( a ); }foo( 2 );(1)foo(..) 函數(shù)的調(diào)用需要對(duì) foo 進(jìn)行RHS引用 ,意思是“去找到 foo 的值, 并把它給我?”。
(2)這里還有一個(gè)容易被忽略卻非常重要的細(xì)節(jié)。代碼中隱式的 a=2 操作可能很容易被你忽略掉。這個(gè)操作發(fā)生在 2 被當(dāng)作參數(shù)傳遞給foo(..) 函數(shù)時(shí),2 會(huì)被分配給參數(shù)a。為了給參數(shù)a(隱式地)分配值,需要進(jìn)行一次LHS 查詢(xún)。
(3)console.log(a)這里還有對(duì)a進(jìn)行的RHS引用,并且將得到的值傳給了console.log(..)。console.log(..) 本身也需要一個(gè)引用才能執(zhí)行, 因此會(huì)對(duì)console對(duì)象進(jìn)行RHS查詢(xún),并且檢查得到的值中是否有一個(gè)叫作log的方法。
所以這里一共進(jìn)行了1次LHS查詢(xún)3次RHS查詢(xún)。
讓我們把上面這段代碼的處理過(guò)程想象成一段對(duì)話, 這段對(duì)話可能是下面這樣的。
引擎: 我說(shuō)作用域, 我需要為?foo?進(jìn)行?RHS?引用。 你見(jiàn)過(guò)它嗎?
作用域: 別說(shuō), 我還真見(jiàn)過(guò), 編譯器那小子剛剛聲明了它。 它是一個(gè)函數(shù), 給你。
引擎: 哥們太夠意思了! 好吧, 我來(lái)執(zhí)行一下?foo。
引擎: 作用域, 還有個(gè)事兒。 我需要為?a?進(jìn)行?LHS?引用, 這個(gè)你見(jiàn)過(guò)嗎?
作用域: 這個(gè)也見(jiàn)過(guò), 編譯器最近把它聲名為?foo?的一個(gè)形式參數(shù)了, 拿去吧。
引擎: 大恩不言謝, 你總是這么棒。 現(xiàn)在我要把?2?賦值給?a。
引擎: 哥們, 不好意思又來(lái)打擾你。 我要為?console?進(jìn)行?RHS?引用, 你見(jiàn)過(guò)它嗎?
作用域: 咱倆誰(shuí)跟誰(shuí)啊, 再說(shuō)我就是干這個(gè)。 這個(gè)我也有,?console?是個(gè)內(nèi)置對(duì)象。給你。
引擎: 么么噠。 我得看看這里面是不是有?log(..)。 太好了, 找到了, 是一個(gè)函數(shù)。
引擎: 哥們, 能幫我再找一下對(duì)?a?的?RHS?引用嗎? 雖然我記得它, 但想再確認(rèn)一次。
作用域: 放心吧, 這個(gè)變量沒(méi)有變動(dòng)過(guò), 拿走, 不謝。
引擎: 真棒。 我來(lái)把?a?的值, 也就是?2, 傳遞進(jìn)?log(..)。
----《你所不知道的JavaScript(上)》?P9
?
實(shí)例2:
function foo(a) {var b = a;return a + b; }var c = foo( 2 );?
以上代碼中有3個(gè)LHS與4個(gè)RHS,分析如下:
(1)var c中的c需要被賦值,在賦值操作的左側(cè),所以對(duì)c進(jìn)行LHS引用。
(2)變量c需要被賦值,他的值是foo(2),那么foo(2)的值是多少呢,需要查找foo(2)的值,在賦值操作的右側(cè),所以對(duì)foo(2)進(jìn)行了一次RHS查詢(xún)。
(3)隱含賦值操作,將2傳遞給function foo(a){……}函數(shù)的參數(shù)a,a=2,a在賦值操作的左側(cè),對(duì)a進(jìn)行了一次LHS查詢(xún)。
(4)var b=a;中,b需要被賦值,處在賦值操作的左側(cè),所以對(duì)b進(jìn)行了一次LHS查詢(xún),b的值將從a來(lái),那么右側(cè)的a的值從何而來(lái)呢?這就需要對(duì)賦值操作右側(cè)的a進(jìn)行了一次RHS查詢(xún)。
(5)return a+b;中,需要找到a與b的值的來(lái)源,a與b都在賦值操作的右側(cè),才能得到a+b的值,所以對(duì)a與b都是進(jìn)行一次RHS查詢(xún)。
注:console.log(..) 本身也需要一個(gè)引用才能執(zhí)行,因此會(huì)對(duì)console 對(duì)象進(jìn)行RHS 查詢(xún),并且檢查得到的值中是否有一個(gè)叫作log 的方法。這里不會(huì)再對(duì)log進(jìn)行RHS查詢(xún)。因?yàn)閷?duì)console查詢(xún)完畢后,對(duì)象屬性訪問(wèn)規(guī)則會(huì)接管對(duì)log屬性的訪問(wèn)。也就是說(shuō),如果是訪問(wèn)對(duì)象的屬性就不存在LHS查詢(xún)和RHS查詢(xún)了,找不到就返回undefined。
?
3、總結(jié)
如果查找的目的是對(duì)變量進(jìn)行賦值, 那么就會(huì)使用 LHS 查詢(xún); 如果目的是獲取變量的值, 就會(huì)使用 RHS 查詢(xún)。賦值操作符會(huì)導(dǎo)致 LHS 查詢(xún)。 =操作符或調(diào)用函數(shù)時(shí)傳入?yún)?shù)的操作都會(huì)導(dǎo)致關(guān)聯(lián)作用域的賦值操作。JavaScript 引擎首先會(huì)在代碼執(zhí)行前對(duì)其進(jìn)行編譯, 在這個(gè)過(guò)程中, 像 var a = 2 這樣的聲明會(huì)被分解成兩個(gè)獨(dú)立的步驟:
1. 首先, var a 在其作用域中聲明新變量。 這會(huì)在最開(kāi)始的階段, 也就是代碼執(zhí)行前進(jìn)行。
2. 接下來(lái), a = 2 會(huì)查詢(xún)(LHS 查詢(xún)) 變量 a 并對(duì)其進(jìn)行賦值。
LHS 和 RHS 查詢(xún)都會(huì)在當(dāng)前執(zhí)行作用域中開(kāi)始, 如果有需要(也就是說(shuō)它們沒(méi)有找到所需的標(biāo)識(shí)符), 就會(huì)向上級(jí)作用域繼續(xù)查找目標(biāo)標(biāo)識(shí)符, 這樣每次上升一級(jí)作用域, 最后抵達(dá)全局作用域, 無(wú)論找到或沒(méi)找到都將停止。不成功的 RHS 引用會(huì)導(dǎo)致拋出 ReferenceError 異常。 不成功的 LHS 引用會(huì)導(dǎo)致自動(dòng)隱式地創(chuàng)建一個(gè)全局變量(非嚴(yán)格模式下), 該變量使用 LHS 引用的目標(biāo)作為標(biāo)識(shí)符, 或者拋出 ReferenceError 異常(嚴(yán)格模式下)。
?
總結(jié)
以上是生活随笔為你收集整理的LHS 和 RHS---你所不知道的JavaScript的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 将iPhone照片导出、iCloud照片
- 下一篇: 【会声会影】视频导出、输出时,如何设置参