iT邦幫忙

2022 iThome 鐵人賽

DAY 6
0
Modern Web

就是要搞懂 JavaScript 啦!系列 第 6

Day06 變數查詢:到底是左邊還是右邊啦!

  • 分享至 

  • xImage
  •  

變數查詢

關於變數的使用,這裡讓我們再探討得深入一些。

當程式執行時,對變數的操作分為以下兩種:

  • LHS (Left Hand Side)
  • RHS (Right Hand Side)

從英文全名可以看到,它分別指左邊和右邊,誰的左邊和右邊?是等號,也就是 = 賦值運算子(assignment operator)的左右邊。

如果用數學運算式 x + y = 5 來舉例:
LHS → x + y
RHS → 5

套回到程式邏輯中:

  • LHS → = 的左邊 → 變數賦值
    • 只處理賦值給 = 左邊的變數,不關心變數的值
  • RHS → = 的右邊 → 變數取值
    • = 右邊取出變數的值,無賦值行為

雖然 LHSRHS 的名稱來源於賦值運算子,但這兩者發生時,不一定需要賦值運算子存在,以下進行更詳細的說明:

LHS

  • 全名 Left Hand Side,意指賦值運算子(=)的左側
  • 找到 = 左側的變數並「賦值」的行為
  • 賦值到「目標」上,關注點在變數(容器)本身,與變數的值(內容物)無關
  • 可能透過運算子 = 發生,也可能通過向函式傳遞(賦予)參數而發生

範例

var name = "Carol";
// 將字串 "Carol" 賦值給 name,發生了 LHS 查詢

function foo(a) { ... }
// 調用函數時,傳入的參數被賦值給 a,發生了 LHS 查詢

RHS

  • 全名 Right Hand Side,意指賦值運算子(=)的右側
  • 找到 = 右側的變數並「取值」的行為
  • 從「來源」取出值,關注點在變數(容器)所存放的值(內容物),沒有任何賦值行為

範例

var totalPrice = amount * 2;
// 取得 amount 的值以進行計算,發生了 RHS 查詢

console.log(totalPrice)
// 取得 console 的值,發生了 RHS 查詢
// 程式調用 console 物件內的 log 屬性,發現是一個函式
// 取得 totalPrice 的值來執行 log 函式,發生了 RHS 查詢

同時具有 LHS 和 RHS 的範例

在實作當中,LHS 和 RHS 經常交錯出現,以下舉一些例子:

範例一

var name = "Charles"; // LHS
var king = name;      // RHS + LHS
  1. var name = "Charles"; 賦值一個字串給變數 name
  2. var king = name; 先進行 RHS 取得 name 的值
  3. 用 LHS 賦值給左邊的變數 king

範例二

function foo(a) {
    // 進入函式
    // 2. LHS,將傳入的參數 "Hello" 賦值給 a
	console.log(a);
    // 3. RHS,取得全域物件屬性 console,並執行屬性查詢取得 log
    // 4. RHS,取得 a 的值並進行函式調用,列印出"Hello"	
}

foo("Hello");
// 1. RHS,回傳 foo 的值,發現是函數並進行調用
  1. 遇到 foo(2) 時,程式發出 RHS 查詢,得知 foo 是一個函式,於是傳入參數準備執行。
  2. 進入到 foo 內部後,參數 2 被賦值給 a,發生 LHS 查詢
  3. 同樣是在 foo 內部,遇到 console 時發出 RHS 查詢,找到是全域物件的屬性,並發現 console.log 是一個函式。
  4. console.log( a ); 時發生 RHS 查詢,找到 a 的值並回傳執行。

function foo(){...} 的部分 ,已在編譯時期處理完了函式宣告和函式賦值,因此當引擎執行程式時,不會進行 LHS 查詢。


變數查詢錯誤

由於變數是以「參考(Reference)」方式儲存在記憶體中,當變數查詢失敗時,不論是 LHS 或 RHS,程式都會拋出 ReferenceError,意即無法取得記憶體中對應的來源參考。

參考可視為變數在記憶體中的住家地址,程式藉著識別值找到某變數,就是依照參考去對應變數在記憶體中所處的位置。

如果兩個變數的參考相同,代表他們指向記憶體相同的位置。當程式改變其中一個變數的內容,等同於改變擁有相同地址的另一個變數的內容。

以下分別細說 LHS 和 RHS 錯誤發生時的狀況:

LHS 錯誤

  • 無法找到變數,導致「賦值失敗」時產生。
  • 除了函式內部的賦值之外,其他的 LHS 錯誤都發生在編譯過程中,所以不會出現編譯結果。

LHS 錯誤的豁免

在 JS 的「預設模式(Default Mode)」下執行 LHS 查詢卻找不到該變數時,全域作用域會直接創造一個新變數,並回傳這個變數。

這種情況發生有兩種可能,一是試圖賦值給從未宣告的變數,二是該變數不在當前可合法存取的作用域範圍內。

ES5 以後新增的「嚴謹模式(Strict Mode)」則不允許自動/隱含地創建全域變數,LHS 查詢失敗時,引擎依舊會拋出 ReferenceError 錯誤。

RHS 錯誤

  • 無法找到變數,導致「取值失敗」時產生。
  • RHS 在運作後才會執行,在編譯過程中不會出現,所以 RHS 錯誤直到執行階段才會發現。

RHS 在查詢成功取得變數的值後,如果對該值進行不合法的行為(指這個值不可能做到的事情,比方說將非函式作為函式調用),則程式會拋出 TypeError


參考資料


上一篇
Day05 變數──值的容器
下一篇
Day07 變數存在的泡泡空間──作用域
系列文
就是要搞懂 JavaScript 啦!73
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言