之前講的是常用的邏輯運算子,而有一個比較特別的,寫法是兩個問號。
之前看不太懂,趁著今天研究出來順便寫自己的理解,接下來就直接開始。
??
根據MDN的解釋,當左邊的值是null
或是undefined
時,會回傳右邊的值,假如不是null
或是undefined
就會回傳左邊的值。
還記得前天講的||
嗎?
||
是碰到第一個真值就回傳。
而當一個值,如果它不是null
也不是undefined
,那它就會是defined
,意思是一個已經定義的值。
所以||
跟??
來做比較的話:
??
會回傳第一個已經定義的值||
會回傳第一個遇到的真值(true)來試試看 =>
左邊是null
時,會回傳右邊的值,左邊不是null
或是undefined
,就會直接回傳左邊的值。
console.log(null ?? 100); // 100
console.log(50 ?? null); // 50
MDN只有說左右兩側,測試看看假如兩組值以上的狀況。
console.log(null ?? null ?? 100 ?? 50); // 100
console.log(50 ?? null ?? null ?? 100); // 50
也是一樣效果,會回傳第一個已經定義的值,讓我想到一個問題,如果全部都沒有定義的值呢?
console.log(null ?? undefined); // undefined
console.log(undefined ?? null); // null
結果來看會回傳最後一個沒定義的值。
還有就是MDN裡面有提到說,不能跟||
及&&
共用。
console.log(null ?? "1" || null); // SyntaxError
console.log(null ?? "2" && null); // SyntaxError
把目前的資訊整理一下。
??
主要用來邏輯判斷定義的值及未定義的值。
要是遇到第一個已經定義的值就直接回傳,否則就一直向右尋找,要是都沒有的話,就回傳最後一個未定義的值,然後不能跟其他邏輯運算子共用。
可以用在需要提供默認值的場合。
比如說,如果fruit
的值不是不是null
也不是undefined
,就會顯示fruit
的值,不然就顯示字串水果
。
在這裡字串水果
就是fruit
的默認值。
let fruit = "蘋果";
console.log(fruit ?? "水果"); // 蘋果
let fruit = undefined;
console.log(fruit ?? "水果"); // 水果
假如今天有一家水果店,開放標一顆蘋果,就可以利用??
來判斷是誰搶到了,不買的人就用null
表示,會按照順序問下去。
let first = null;
let second = null;
let third = "Angela";
console.log(first ?? second ?? third ?? "流標"); // Angela
有人可能會問說,那幹嘛不用||
就好?
依據碰到第一個真值就回傳的特性,在上面的例子使用||
結果也會完全一模一樣。
let first = null;
let second = null;
let third = "Angela";
console.log(first || second || third || "流標"); // Angela
這邊要先從發展的角度來說。
||
,現在的??
??
是很後期大約在ES11
才出現的新語法,代表著是先有||
,才有??
的誕生。
而會有這種狀況的產生,我的理解是因為有些||
沒辦法顧及的狀況,所以才需要有一個跟||
很像但又不完全一樣的語法。
而這個答案其實前面就有暗示了。
||
會回傳真值
,而??
會回傳已定義的值
。
這邊代表一件事情,那就是||
只能判斷真值跟假值,也就是說,全部的假值都不會被回傳。
不論是0
,“”
,NaN
,null
,undefined
,全部都不會被回傳。||
沒有辦法區分它們。
這樣會造成很多麻煩的點在於,假如我今天想要的值就是0
,那麼使用||
將會沒辦法達到我想要預期的結果。
let scope = 0;
console.log(scope || "默認值"); // 默認值
console.log(scope ?? "默認值"); // 0
我的變數值想設定成0
,但是會發現說使用||
會沒有辦法顯示出來,會直接跳到默認值,因為對於||
來說,0
是假值,不會回傳。
但如果使用??
就不會發生這種問題,它會先判斷是不是有定義的值,如果不是非定義的值(null
,undefined
),那就會是有效值,就不會被替換成默認值了。
[1] MDN - Nullish coalescing operator (??)