空值連接運算子寫成兩個問號 ??
。
由於它以相同的方式處理 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…)