空值連接運算子寫成兩個問號 ??。
由於它以相同的方式處理 null 和 undefined,我們將在本文中使用一個特殊術語。為簡潔起見,當一個值既不是 null 也不是 undefined 時,我們將說該值是「已定義」。
a ?? b 的結果是
- 如果
a已定義,則為a, - 如果
a未定義,則為b。
換句話說,?? 會傳回第一個引數,如果它不是 null/undefined 的話。否則,傳回第二個引數。
空值連接運算子並不是什麼完全新穎的東西。它只是一個漂亮的語法,用於取得兩個值中的第一個「已定義」值。
我們可以使用我們已經知道的運算子來改寫 result = a ?? b,如下所示
result = (a !== null && a !== undefined) ? a : b;
現在應該絕對清楚 ?? 的作用了。讓我們看看它在哪裡有幫助。
?? 的常見用途是提供預設值。
例如,如果 user 的值不是 null/undefined,我們會顯示 user,否則顯示 Anonymous
let user;
alert(user ?? "Anonymous"); // Anonymous (user is undefined)
以下是將 user 指定給名稱的範例
let user = "John";
alert(user ?? "Anonymous"); // John (user is not null/undefined)
我們也可以使用一系列 ?? 從不是 null/undefined 的清單中選取第一個值。
假設我們在變數 firstName、lastName 或 nickName 中有使用者的資料。如果使用者決定不填入對應的值,它們都可能未定義。
我們希望使用其中一個變數顯示使用者名稱,或者如果它們都是 null/undefined,則顯示「Anonymous」。
讓我們使用 ?? 運算子來執行此操作
let firstName = null;
let lastName = null;
let nickName = "Supercoder";
// shows the first defined value:
alert(firstName ?? lastName ?? nickName ?? "Anonymous"); // Supercoder
與 || 比較
OR || 運算子可以與 ?? 以相同的方式使用,如 前一章節 所述。
例如,在上面的程式碼中,我們可以用 || 取代 ??,仍然可以得到相同的結果
let firstName = null;
let lastName = null;
let nickName = "Supercoder";
// shows the first truthy value:
alert(firstName || lastName || nickName || "Anonymous"); // Supercoder
從歷史上來看,OR || 運算子是最早出現的。它從 JavaScript 的開端就存在,因此開發人員長期以來都將它用於此類目的。
另一方面,nullish 合併運算子 ?? 直到最近才加入 JavaScript,而原因是人們對 || 不太滿意。
它們之間的重要區別在於
||傳回第一個 真值。??傳回第一個 已定義 的值。
換句話說,|| 不區分 false、0、空字串 "" 和 null/undefined。它們都是相同的 - 假值。如果其中任何一個是 || 的第一個參數,那麼我們將得到第二個參數作為結果。
然而,在實務上,我們可能只想在變數為 null/undefined 時使用預設值。也就是說,當值確實未知/未設定時。
例如,考慮以下情況
let height = 0;
alert(height || 100); // 100
alert(height ?? 100); // 0
height || 100檢查height是否為假值,而它是0,確實為假值。- 因此
||的結果是第二個參數100。
- 因此
height ?? 100檢查height是否為null/undefined,而它不是,- 因此結果是「原樣」的
height,也就是0。
- 因此結果是「原樣」的
實際上,零高度通常是有效值,不應替換為預設值。因此 ?? 執行的是正確的動作。
優先順序
?? 算子的優先順序與 || 相同。它們在 MDN 表格 中都等於 3。
這表示與 || 一樣,空值合併算子 ?? 會在 = 和 ? 之前評估,但在 +、* 等大多數其他運算之後評估。
因此我們可能需要在類似這樣的表達式中加入括號
let height = null;
let width = null;
// important: use parentheses
let area = (height ?? 100) * (width ?? 50);
alert(area); // 5000
否則,如果我們省略括號,由於 * 的優先順序高於 ??,因此它會先執行,導致結果不正確。
// without parentheses
let area = height ?? 100 * width ?? 50;
// ...works this way (not what we want):
let area = height ?? (100 * width) ?? 50;
將 ?? 與 && 或 || 搭配使用
由於安全原因,JavaScript 禁止將 ?? 與 && 和 || 算子一起使用,除非優先順序已明確指定括號。
以下程式碼會觸發語法錯誤
let x = 1 && 2 ?? 3; // Syntax error
這個限制當然有爭議,它被加入語言規格中,目的是為了避免程式設計錯誤,當人們開始從 || 切換到 ?? 時。
使用明確的括號來解決它
let x = (1 && 2) ?? 3; // Works
alert(x); // 2
摘要
-
空值合併算子
??提供了一種簡短的方法,可從清單中選擇第一個「已定義」的值。它用於將預設值指定給變數
// set height=100, if height is null or undefined height = height ?? 100; -
算子
??的優先順序非常低,僅比?和=高一點,因此在表達式中使用它時,請考慮加入括號。 -
禁止在沒有明確括號的情況下將它與
||或&&一起使用。
留言
<code>標籤,若要插入多行程式碼 – 請將它們包覆在<pre>標籤中,若要插入超過 10 行程式碼 – 請使用沙盒 (plnkr、jsbin、codepen…)