前言

之前講的是常用的邏輯運算子,而有一個比較特別的,寫法是兩個問號。
之前看不太懂,趁著今天研究出來順便寫自己的理解,接下來就直接開始。

??

根據 MDN 的解釋,當左邊的值是null或是undefined時,會回傳右邊的值,假如不是null或是undefined就會回傳左邊的值。

還記得前天講的||嗎?

||是碰到第一個真值就回傳。

而當一個值,如果它不是null也不是undefined,那它就會是defined,意思是一個已經定義的值。

所以||??來做比較的話:

  • ??會回傳第一個已經定義的值
  • ||會回傳第一個遇到的真值(true)

來試試看 =>

左邊是null時,會回傳右邊的值,左邊不是null或是undefined,就會直接回傳左邊的值。

1
2
console.log(null ?? 100); // 100
console.log(50 ?? null); // 50

MDN 只有說左右兩側,測試看看假如兩組值以上的狀況。

1
2
console.log(null ?? null ?? 100 ?? 50); // 100
console.log(50 ?? null ?? null ?? 100); // 50

也是一樣效果,會回傳第一個已經定義的值,讓我想到一個問題,如果全部都沒有定義的值呢?

1
2
console.log(null ?? undefined); // undefined
console.log(undefined ?? null); // null

結果來看會回傳最後一個沒定義的值。

還有就是 MDN 裡面有提到說,不能跟||&&共用。

1
2
console.log(null ?? "1" || null); // SyntaxError
console.log(null ?? "2" && null); // SyntaxError

把目前的資訊整理一下。

??主要用來邏輯判斷定義的值及未定義的值。

要是遇到第一個已經定義的值就直接回傳,否則就一直向右尋找,要是都沒有的話,就回傳最後一個未定義的值,然後不能跟其他邏輯運算子共用。

使用情境

可以用在需要提供默認值的場合。

比如說,如果fruit的值不是不是null也不是undefined,就會顯示fruit的值,不然就顯示字串水果

在這裡字串水果就是fruit的默認值。

1
2
let fruit = "蘋果";
console.log(fruit ?? "水果"); // 蘋果
1
2
let fruit = undefined;
console.log(fruit ?? "水果"); // 水果

假如今天有一家水果店,開放標一顆蘋果,就可以利用??來判斷是誰搶到了,不買的人就用null表示,會按照順序問下去。

1
2
3
4
5
let first = null;
let second = null;
let third = "Angela";

console.log(first ?? second ?? third ?? "流標"); // Angela

有人可能會問說,那幹嘛不用||就好?

依據碰到第一個真值就回傳的特性,在上面的例子使用||結果也會完全一模一樣。

1
2
3
4
5
let first = null;
let second = null;
let third = "Angela";

console.log(first || second || third || "流標"); // Angela

這邊要先從發展的角度來說。

過去的||,現在的??

??是很後期大約在ES11才出現的新語法,代表著是先有||,才有??的誕生。

而會有這種狀況的產生,我的理解是因為有些||沒辦法顧及的狀況,所以才需要有一個跟||很像但又不完全一樣的語法。

而這個答案其實前面就有暗示了。

||會回傳真值,而??會回傳已定義的值

這邊代表一件事情,那就是||只能判斷真值跟假值,也就是說,全部的假值都不會被回傳。

不論是0,“”,NaN,null,undefined,全部都不會被回傳。
||沒有辦法區分它們。

這樣會造成很多麻煩的點在於,假如我今天想要的值就是0,那麼使用||將會沒辦法達到我想要預期的結果。

1
2
3
let scope = 0;
console.log(scope || "默認值"); // 默認值
console.log(scope ?? "默認值"); // 0

我的變數值想設定成0,但是會發現說使用||會沒有辦法顯示出來,會直接跳到默認值,因為對於||來說,0是假值,不會回傳。

但如果使用??就不會發生這種問題,它會先判斷是不是有定義的值,如果不是非定義的值(null,undefined),那就會是有效值,就不會被替換成默認值了。

reference

[1] MDN - Nullish coalescing operator (??)