天天看點

JavaScript中的LHS和RHS分析

lhs 和 rhs

對于lhs和rhs,從字面意思來說是​<code>​ left hand side​</code>​和​<code>​ right hand side​</code>​即左手邊和右手邊,一般可以了解為指派操作的左側和右側,然而不能片面的用​<code>​=​</code>​号左邊還說右邊去判斷是​<code>​lhs​</code>​還是​<code>​rhs​</code>​通俗的了解,​

<code>​lhs​</code>​是指派操作即可以看做是在往記憶體中存儲值,而​<code>​rhs​</code>​是取值操作,它是從記憶體中進行檢索。事實上指派操作還有其他幾種形式,是以在概念上最好将其了解為“指派操作的目标是誰(lhs)”以及“誰是指派操作的源頭(rhs)”。

這兩種不同的引用方式對沒有聲明的變量的處理方式上是不同的,而這個不同之處對于我們編寫代碼和分析js引擎報錯是很有益處的。

當對一個變量執行​<code>​rhs​</code>​查詢時,如果周遊該變量所在處的詞法作用域未能找到這個變量,js引擎就會抛出​<code>​ referenceerror​</code>​錯誤如果成功查詢到了這個變量,但是對這個變量執行不合理操作,比如對一個非數組的變量執行下标取值,js引擎就會抛出​<code>​ typeerror​</code>​錯誤,甚至跟你說這個操作對應的隻能是數組。當對一個變量執行​

<code>​lhs​</code>​查詢時,同樣在周遊作用域後無法找到該變量,在非​<code>​es5​</code>​的嚴格模式下,系統就會自動在全局作用域中建立一個同名變量,并将引用轉移到該建立的全局變量中。而在​<code>​es5​</code>​的嚴格模式下,lhs查詢失敗時js引擎會抛出一個同rhs一樣的​<code>​ referenceerror ​</code>​錯誤。![​

JavaScript中的LHS和RHS分析

是以,對lhs查詢和rhs查詢的仔細區分和了解無論是對js執行過程本身的了解還是分析錯誤都是有所好處的。

在js語言特點

javascript在類型上通常會被歸類為“動态”或“解釋執行”語言,但事實上它是一門編譯語言。

javascript是世界上最流行的腳本語言,因為你在電腦、手機、平闆上浏覽的所有的網頁,以及無數基于html5的手機app,互動邏輯都是由javascript驅動的。 簡單地說,javascript是一種運作在浏覽器中的解釋型的程式設計語言。

不過這種語言與傳統的編譯語言還是有點不同,它不是提前編譯的,編譯結果也不能在分布式系統上進行移植,做過前端項目部署的同學,也會發現,我們将項目編譯完成之後是個​<code>​dist​</code>​檔案,之後将這整個檔案直接放在web伺服器上面,如nginx、tomcat等,這個是個很純粹的單機部署。

比如說,執行一個指派語句,我們的javascript引擎要做多少事呢?

事實上做了兩步,javascript 會将其看成兩句聲明:​<code>​var girlfriend;​</code>​和​<code>​girlfriend = 'naug';​</code>​

定義聲明在編譯階段進行

指派聲明會被留在原地等待執行階段。

變量的指派操作會執行兩個動作,首先編譯器會在目前作用域中聲明一個變量(如果之前沒有聲明過),然後在運作時引擎會在作用域中查找該變量,如果能夠找到就會對它指派。

而要講的lhs 和 rhs就是上面說的對變量的兩種查找操作,查找的過程是由作用域(詞法作用域)進行協助,在編譯的第二步中執行。

前面我們說到,​<code>​lhs​</code>​是指派操作就是在往記憶體中存儲值,而​<code>​rhs​</code>​是取值操作可以從記憶體中檢索值,那麼基于這個資訊點,我們再來分析一個複雜一些的例子

問,這個例子中一共用了多少個lhs和rhs?

答,3個lhs和3個rhs

lhs

- 函數裡面隐藏的​<code>​people = 'naug'​</code>​(隐式變量配置設定),當調用​<code>​together('naug')​</code>​時,需要将實參​<code>​naug​</code>​指派給形參​<code>​people​</code>​,是以對​<code>​people​</code>​需要進行​<code>​lhs​</code>​操作 - 對于​

<code>​girlfriend = people​</code>​ ,中,girlfriend在指派操作的左邊,即将該變量往該作用域空間所在記憶體區間儲值,也就是進行lhs操作 - ​

<code>​luckygirl = ... ​</code>​,中​<code>​luckygirl​</code>​在指派操作的左邊,需要為該變量在記憶體中進行儲值,即對​<code>​luckygirl​</code>​進行​<code>​lhs​</code>​操作

rhs

- ​<code>​girlfriend = people​</code>​ ,中​<code>​people​</code>​在指派操作的右邊,​<code>​javascript​</code>​引擎需要對其進行取值操作,是以進行​<code>​rhs​</code>​查詢 - ​

<code>​return girlfriend​</code>​,由于需要知道​<code>​girlfriend​</code>​的值,是以進行​<code>​rhs​</code>​查詢到​<code>​girlfriend​</code>​的值 - ​

<code>​luckygirl = together('naug')​</code>​,中​<code>​together('naug')​</code>​在指派操作的右邊是以需要知道該函數執行之後的值

小結:如果查找的目的是對變量進行指派,那麼就會使用lhs查詢;如果目的是擷取變量的值,就會使用rhs查詢。

因為在變量還沒有聲明(在任何作用域中都無法找到該變量)情況下,這兩種查詢行為是不一樣的。

對于作用域的分析可以看一下這篇文章​​關于js中的作用域中的沉思​​,這裡想說的是lhs和rhs都會在目前執行作用域中開始,如果有需要(也就是說他們沒有找到所需的辨別符),就會向上級作用域繼續查找目标辨別符,依次上升一次作用域,最後抵達全局作用域,最後無論找到或沒找到都将到此為止

總結

不成功的rhs引用會導緻抛出​<code>​referenceerror​</code>​異常。不成功的lhs引用會導緻自動隐式地建立一個全局變量(非嚴格模式下),該變量使用lhs引用的目标作為辨別符,或者抛出​<code>​referenceerror​</code>​異常(嚴格模式下)。

參考資料

《你不知道的javascript(上卷)》

https://www.liaoxuefeng.com/wiki/1022910821149312

繼續閱讀