LHS 和 RHS----你所不知道的JavaScript系列

來源:互聯網
上載者:User

標籤:type   類型   nts   info   script   有一個   變數   也有   運行時   

 

變數的賦值操作會執行兩個動作, 首先編譯器會在當前範圍中聲明一個變數(如果之前沒有聲明過), 然後在運行時引擎會在範圍中尋找該變數, 如果能夠找到就會對它賦值。----《你所不知道的JavaScript(上)》 P7

而要講的 LHS 和 RHS 就是上面說的對變數的兩種尋找操作,尋找的過程是由範圍(詞法範圍)進行協助,但是引擎執行怎樣的尋找, 會影響最終的尋找結果。 

1、LHS(Left Hand Side)和 RHS(Right Hand Side)

當變數出現在賦值操作的左側時進行 LHS 查詢, 出現在右側時進行 RHS 查詢。講得更準確一點, RHS 查詢與簡單地尋找某個變數的值別無二致, 而 LHS 查詢則是試圖找到變數的容器本身, 從而可以對其賦值。 從這個角度說, RHS 並不是真正意義上的“賦值操作的右側”, 更準確地說是“非左側”。  ----《你所不知道的JavaScript(上)》 P7

  簡單來說,

  (1)LHS查詢指的是找到變數的容器本身,從而可以對其進行賦值。也就是找到賦值操作的目標。LHS查詢的時候會沿著範圍鏈進行查詢,找到的話就會將值賦值給這個變數,如果到達範圍頂端仍然找不到,就會在範圍鏈頂端建立這個變數(在strict 模式中 LHS 查詢失敗時, 並不會建立並返回一個全域變數, 引擎會拋出同 RHS 查詢失敗時類似的 ReferenceError 異常 

var a = 2;

這裡對 a 的引用則是 LHS 引用, 因為實際上我們並不關心當前a的值是什麼, 只是想要為 =2 這個賦值操作找到一個目標。

  (2)RHS查詢就是普通的查詢變數的值,即擷取變數的值。RHS查詢的時候會沿著範圍鏈進行查詢,找到的話就會取得這個值並返回,如果到達範圍頂端仍然找不到,引擎就會拋出 ReferenceError異常如果 RHS 查詢找到了一個變數, 但是你嘗試對這個變數的值進行不合理的操作,比如試圖對一個非函數類型的值進行函數調用, 或著引用 null 或 undefined 類型的值中屬性, 那麼引擎會拋出另外一種類型的異常, 叫作 TypeError。
(註:ReferenceError 同範圍判別失敗相關, 而 TypeError 則代表範圍判別成功了, 但是對結果的操作是非法或不合理的。)

  舉個栗子:

console.log(a);

這裡的a就是一個RHS引用,因為console.log需要擷取到a的值才能輸出a的值。當然這裡的console.log也是一個RHS引用,這裡對console 對象進行RHS 查詢,並且檢查得到的值中是否有一個叫作log 的方法。例子中的a因為沒有聲明過,所以會拋出錯誤。如所示:

 

 

2、執行個體詳解

執行個體1:

function foo(a) {  console.log( a ); }foo( 2 );

(1)foo(..) 函數的調用需要對 foo 進行RHS引用 ,意思是“去找到 foo 的值, 並把它給我 ”。

(2)這裡還有一個容易被忽略卻非常重要的細節。代碼中隱式的 a=2 操作可能很容易被你忽略掉。這個操作發生在 2 被當作參數傳遞給foo(..) 函數時,2 會被分配給參數a。為了給參數a(隱式地)分配值,需要進行一次LHS 查詢。

(3)console.log(a)這裡還有對a進行的RHS引用,並且將得到的值傳給了console.log(..)。console.log(..) 本身也需要一個引用才能執行, 因此會對console對象進行RHS查詢,並且檢查得到的值中是否有一個叫作log的方法。

所以這裡一共進行了1次LHS查詢3次RHS查詢。

讓我們把上面這段代碼的處理過程想象成一段對話, 這段對話可能是下面這樣的。

  引擎: 我說範圍, 我需要為 foo 進行 RHS 引用。 你見過它嗎?

  範圍: 別說, 我還真見過, 編譯器那小子剛剛聲明了它。 它是一個函數, 給你。

  引擎: 哥們太夠意思了! 好吧, 我來執行一下 foo。

  引擎: 範圍, 還有個事兒。 我需要為 a 進行 LHS 引用, 這個你見過嗎?

  範圍: 這個也見過, 編譯器最近把它聲名為 foo 的一個形式參數了, 拿去吧。

  引擎: 大恩不言謝, 你總是這麼棒。 現在我要把 2 賦值給 a。

  引擎: 哥們, 不好意思又來打擾你。 我要為 console 進行 RHS 引用, 你見過它嗎?

  範圍: 咱倆誰跟誰啊, 再說我就是幹這個。 這個我也有, console 是個內建對象。給你。

  引擎: 麼麼噠。 我得看看這裡面是不是有 log(..)。 太好了, 找到了, 是一個函數。

  引擎: 哥們, 能幫我再找一下對 a 的 RHS 引用嗎? 雖然我記得它, 但想再確認一次。

  範圍: 放心吧, 這個變數沒有變動過, 拿走, 不謝。

  引擎: 真棒。 我來把 a 的值, 也就是 2, 傳遞進 log(..)。

  ----《你所不知道的JavaScript(上)》 P9

 

執行個體2:

function foo(a) {    var b = a;    return a + b;}var c = foo( 2 );

以上代碼中有3個LHS與4個RHS,分析如下:

(1)var c中的c需要被賦值,在賦值操作的左側,所以對c進行LHS引用。

(2)變數c需要被賦值,他的值是foo(2),那麼foo(2)的值是多少呢,需要尋找foo(2)的值,在賦值操作的右側,所以對foo(2)進行了一次RHS查詢。

(3)隱含賦值操作,將2傳遞給function foo(a){……}函數的參數a,a=2,a在賦值操作的左側,對a進行了一次LHS查詢。

(4)var b=a;中,b需要被賦值,處在賦值操作的左側,所以對b進行了一次LHS查詢,b的值將從a來,那麼右側的a的值從何而來呢?這就需要對賦值操作右側的a進行了一次RHS查詢。

(5)return a+b;中,需要找到a與b的值的來源,a與b都在賦值操作的右側,才能得到a+b的值,所以對a與b都是進行一次RHS查詢。

 

3、小結:

如果尋找的目的是對變數進行賦值, 那麼就會使用 LHS 查詢; 如果目的是擷取變數的值, 就會使用 RHS 查詢。賦值操作符會導致 LHS 查詢。 =操作符或調用函數時傳入參數的操作都會導致關聯範圍的賦值操作。JavaScript 引擎首先會在代碼執行前對其進行編譯, 在這個過程中, 像 var a = 2 這樣的聲明會被分解成兩個獨立的步驟:

1. 首先, var a 在其範圍中聲明新變數。 這會在最開始的階段, 也就是代碼執行前進行。

2. 接下來, a = 2 會查詢(LHS 查詢) 變數 a 並對其進行賦值。

LHS 和 RHS 查詢都會在當前執行範圍中開始, 如果有需要(也就是說它們沒有找到所需的標識符), 就會向上級範圍繼續尋找目標標識符, 這樣每次上升一級範圍, 最後抵達全域範圍, 無論找到或沒找到都將停止。不成功的 RHS 引用會導致拋出 ReferenceError 異常。 不成功的 LHS 引用會導致自動隱式地建立一個全域變數(非strict 模式下), 該變數使用 LHS 引用的目標作為標識符, 或者拋出 ReferenceError 異常(strict 模式下)。

 

 

LHS 和 RHS----你所不知道的JavaScript系列

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.