LHS与RHS查询
本文基于《你不知道的Javascript》編寫。
JavaScript中在預編譯后執行代碼時對變量的查詢分為LHS(Left-Hand-Side)查詢和RHS(Right-Hand-Side)查詢。
是一個賦值操作的左側和右側的意思;
(一)看一個轉換后的例子:
function foo(a) {console.log( a ); // 2 } foo( 2 );代碼執行原理圖解:
(二)我的分析
示例:
分析:
(1)從 var c = foo( 2 );入手.c的賦值操作需要對c進行一次LHS查詢,foo(2)需要進行一次RHS查詢,去獲取 foo(2) 的值.(2)進入函數聲明,foo(a){},這里有一個隱式賦值操作,需要對a進行一次LHS查詢,判斷作用域中是否存在名為a的變量,若存在則直接賦值a=2;若不存在,如果是嚴格模式下,則報ReferenceError:a is not defined.如果非嚴格模式,則創建一個a的全局變量,并直接賦值a=2;(3)var b = a;需要對b進行一次LHS查詢,以及對a進行一次RHS查詢以獲得a的值;(4)return a + b;需要分別對a和b進行RHS查詢;(三)為什么區分 LHS 和 RHS 是一件重要的事情?
因為在變量還沒有聲明(在任何作用域中都無法找到該變量)的情況下,這兩種查詢的行為是不一樣的。
考慮如下代碼:
第一次對 b 進行 RHS 查詢時是無法找到該變量的。也就是說,這是一個“未聲明”的變量,因為在任何相關的作用域中都無法找到它。
如果 RHS 查詢在所有嵌套的作用域中遍尋不到所需的變量,引擎就會拋出 ReferenceError異常。值得注意的是,ReferenceError 是非常重要的異常類型。
相較之下,當引擎執行 LHS 查詢時,如果在頂層(全局作用域)中也無法找到目標變量,全局作用域中就會創建一個具有該名稱的變量,并將其返還給引擎,前提是程序運行在非“嚴格模式”下。
“不,這個變量之前并不存在,但是我很熱心地幫你創建了一個。”
ES5 中引入了“嚴格模式”。同正常模式,或者說寬松 / 懶惰模式相比,嚴格模式在行為上有很多不同。其中一個不同的行為是嚴格模式禁止自動或隱式地創建全局變量。因此,在嚴格模式中 LHS 查詢失敗時,并不會創建并返回一個全局變量,引擎會拋出同 RHS 查詢失敗時類似的 ReferenceError 異常。
接下來,如果 RHS 查詢找到了一個變量,但是你嘗試對這個變量的值進行不合理的操作,比如試圖對一個非函數類型的值進行函數調用,或著引用 null 或 undefined 類型的值中的屬性,那么引擎會拋出另外一種類型的異常,叫作 TypeError。
ReferenceError 同作用域判別失敗相關,而 TypeError 則代表作用域判別成功了,但是結果的操作是非法或不合理的。
(四)小結
-
作用域是一套規則,用于確定在何處以及如何查找變量(標識符)。
-
如果查找的目的是對變量進行賦值,就會使用 LHS 查詢;如果目的是獲取變量的值,就會用 RHS 查詢。
-
賦值操作會導致 LHS 查詢。 = 操作符或調用函數時傳入參數的操作都會導致關聯作用域的賦值操作, 即都會導致 LHS 查詢。
-
JavaScript 引擎首先會在代碼執行前對其進行編譯,在這個過程中,像var a = 2 這樣的聲明會被分解成兩個獨立的步驟:
1.首先,var a在其作用域中聲明新變量。這會在最開始的階段,也就是代碼執行前進行。
2.接下來,a = 2會查詢(LHS查詢)變量 a 并對其進行賦值。 -
LHS 和 RHS
查詢都會在當前執行作用域中開始,如果有需要(也就是說它們沒有找到所需的標識符),就會向上級作用域繼續查找目標標識符,這樣每次上升一級作用域,最后到達全局作用域,無論找到或沒找到都將停止。 -
不成功的 RHS 引用會導致拋出 ReferenceError 異常。不成功的 LHS引用會導致自動隱式地創建一個全局變量(非嚴格模式下),該變量使用 LHS 引用的目標作為標識符,或者拋出ReferenceError異常(嚴格模式下)。
總結
- 上一篇: UDT 最新源码分析(三) -- UDT
- 下一篇: 【实例】Python tkinter 实