快速理解JavaScript 中的 LHS 和 RHS 查詢

簡述編譯原理

  • JavaScript 程序中的一段源代碼在執行以前會經歷三個步驟,統稱爲 編譯
  1. 分詞/詞法分析
  2. 解析/語法分析
  3. 代碼生成
  • 先看原書對一個賦值操做的拆解說明:

變量的賦值操做會執行兩個動做,首先編譯器會在當前做用域中聲明一個變量(若是以前沒有聲明過),而後在運行時引擎會在做用域中查找該變量,若是可以找到就會對它賦值。 --- 《你不知道的JavaScript(上卷)》 P7html

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

LHS 和 RHS

  • 字面意思實際上是 Left Hand SideRight Hand Side 即左手邊和右手邊
  • 通常能夠理解爲 賦值操做的左側和右側

先看個例子一

console.log(a);
  • 這裏對 a 是一個 RHS 引用,由於 a 並無賦予任何值,目的是爲了取到 a 的值並打印出來。
a = 2;
  • 這裏對 a 是一個 LHS 引用,由於實際上咱們不關心當前的值是什麼,只是想要把 a 賦值爲 2。

再看例子二

function foo(a) {
    console.log(a); // 2
}
foo(2);
  • 最後一行foo(..)函數的調用須要對 foo 進行 RHS 引用,意味着是取到 foo 的值,而且 (..)意味着 foo 須要被執行,所以它最好是一個函數類型的值
  • 其中有一個容易被忽略的隱式賦值操做 a = 2,它發生在 2 被當作實參傳入 foo 中時。即實參 2 傳給了形參 a,須要一個 LHS 查詢
  • console 那一行還有對 a 的一次 RHS 引用(或者叫查詢),同時console.log(..)自己也須要一個 RHS 引用,即對 console 對象進行 RHS 查詢,而且檢查獲得的值中是否有一個叫作 log 的方法。
  • 書中有一段引擎和做用域的對話,有助於很好的理解例子二,see YDKJS github

小測驗

function foo(a) {
    var b = a;
    return a + b;
}
var c = foo(2);
  • 試試找出其中的3處 LHS 查詢,4處 RHS 查詢

<!--more-->git

答案github

  1. LHS 查詢:
  • c = ..;
  • a = 2(隱式變量分配)
  • b = ..
  1. RHS 查詢
  • foo(2..
  • = a;
  • a ..
  • .. b

小結

參考原書中文版P12,英文版見 githubide

  • 做用域是一套規則,用於肯定在何處以及如何查找變量(標識符)。
  • 若是查找的目的是對變量進行賦值,就會使用 LHS 查詢;若是目的是獲取變量的值,就會用 RHS 查詢。
  • 賦值操做會致使 LHS 查詢。 = 操做符或調用函數時傳入參數的操做都會致使關聯做用域的賦值操做, 即都會致使 LHS 查詢。
  • JavaScript 引擎首先會在代碼執行前對其進行編譯,在這個過程當中,像var a = 2 這樣的聲明會被分解成兩個獨立的步驟:函數

    1. 首先,var a在其做用域中聲明新變量。這會在最開始的階段,也就是代碼執行前進行。
    2. 接下來,a = 2會查詢(LHS查詢)變量 a 並對其進行賦值。
  • LHS 和 RHS 查詢都會在當前執行做用域中開始,若是有須要(也就是說它們沒有找到所需的標識符),就會向上級做用域繼續查找目標標識符,這樣每次上升一級做用域,最後到達全局做用域,不管找到或沒找到都將中止。
  • 不成功的 RHS 引用會致使拋出 ReferenceError 異常。不成功的 LHS 引用會致使自動隱式地建立一個全局變量(非嚴格模式下),該變量使用 LHS 引用的目標做爲標識符,或者拋出 ReferenceError 異常(嚴格模式下)。

參考

相關文章
相關標籤/搜索