avatarMike Huang

Free AI web copilot to create summaries, insights and extended knowledge, download it at here

4188

Abstract

edBag</span> = arg.<span class="hljs-property">isNeedBag</span> !== <span class="hljs-literal">false</span>;</pre></div><p id="71cf">這也是為什麼在 ECMA 2020 介紹了 Nullish coalescing operator (??)。</p><h1 id="fc9d">空值合併運算符 Nullish coalescing operator (??)</h1><p id="ffca">空值合併運算符(Nullish coalescing operator)和 Logical OR 的功能非常相似,但相比之下更為嚴謹:與其單純判斷是否為「Falsy」值,空值合併運算符判定是否為「Nullish」值——因此唯有當第一個運算元為「<code>undefined</code>」或「<code>null</code>」時,才會回傳第二個運算元。</p> <figure id="dc62"> <div> <div>

            <iframe class="gist-iframe" src="/gist/smallpaes/437f094c5a56436bd25b782085621c28.js" allowfullscreen="" frameborder="0" height="undefined" width="undefined">
          </div>
        </div>
    </figure></iframe></div></div></figure><p id="54c0">如此一來,可以真實反映目標值是否未被給定或明確被給定為 <code>undefined</code> 或 <code>null</code>:</p><p id="1586">回頭改寫訂單的範例,由於布林值 <code>false</code> 和數值 <code>0</code> 都不算 Nullish 值,因此 <code>firstOrder.isNeedBag</code> 和 <code>firstOrder.sugarNum</code> 在改寫後都能得到正確的回傳值。而由於訂單商品我們仍希望保有空字串的判斷,所以我們還是能繼續使用 Logical OR,因此 <code>firstOrder.item</code> 最終被給予預設值 <code>Tea</code>。</p>
    <figure id="a1de">
        <div>
          <div>
            
            <iframe class="gist-iframe" src="/gist/smallpaes/859f3916f14505fa7128cfd2a74ac2d9.js" allowfullscreen="" frameborder="0" height="undefined" width="undefined">
          </div>
        </div>
    </figure></iframe></div></div></figure><h2 id="ddb2">使用上的注意事項</h2><p id="99db">在 JavaScirpt 中有各種運算子(Operator),而理論上要在一個運算式(Expression)使用多個運算子是沒有問題的。然而,當一個運算式中包含了多個運算子時,就會遇到「哪個運算子該先被執行」。</p><p id="a358">這其實就跟以下呈現的加減乘除一樣,由於我們人類知道「先乘除後加減」的規則,因此我們會先執行 3 * 2,再將結果 6 拿去執行 6 + 1,最終獲得 7。然而,電腦沒有這方面的知識,因此如果照著由左至右一一執行,最終將得到 8 這個答案:</p><div id="7650"><pre><span class="hljs-number">1</span> + <span class="hljs-number">3</span> * <span class="hljs-number">2</span> <span class="hljs-comment">// 7</span></pre></div><p id="03d7"><b>運算子優先序(Operator precedence)</b></p><p id="4f30">JavaScript 將運算子歸類成不同的位階,以此來決定執行的順序:<a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Operator_Precedence">運算子優先序</a>。從位階表中能發現乘除法比加減法位階來得高,因此電腦在這方面的計算也能得出正確的答案。</p><figure id="1c93"><img src="https://cdn-images-1.readmedium.com/v2/resize:fit:800/1*NlwkkCPEjre3FvyZTaRt9A.png"><figcaption></figcaption></figure><p id="1f2f">邏輯運算子中 Logical AND (<code>&amp;&amp;</code>)的位階則高於 Logical OR(<code>||</code>),因此當一個運算式中(如下範例)同時運用了 Logical AND 和 LogicalOR,前者將優先被執行。然而,如果希望範例中的 Ligical OR 先被執行,則可以使用位階更高的 <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Grouping">GroupingOperator</a> <code>()</code> 來達成效果。</p><div id="a374"><pre><span class="hljs-literal">false</span> &amp;&amp; <span class="hljs-literal">false</span> || <span class="hljs-literal">true</span> // <span class="hljs-literal">true</span>

<span class="hljs-literal">false</span> && (<span class="hljs-literal">false</span> || <span class="hljs-literal">true</span>) // <span class="hljs-literal">false</span></pre></div><p id="a4ca">空值合併運算符(Nullish Coalescing Operator)的位階和 Logical OR 相同,但比 Logical AND 還來得低。若將空值運算符與另外兩個運算符「直接串接在一起合併使用」非常容易出現預期外的結果,因此是<b>「不被允許」</b>的,你會看到語法錯誤的訊息:</p><div id="a787"><pre><span class="hljs-literal">false</span> || <span class="hljs-literal">undefined</span> ?? <span class="hljs-string">"default value"</span>; <span class="hljs-comment">// Uncaught Syntax Error:Unexpected token '??'</span></pre></div><p id="e9a6">相反的,使用上開發者必須使用括號 <code>()</code> 明確的指定優先序:</p><div id="013b"><pre>(<span class="hljs-literal">false</span> |<span class="hljs-params"></span>| undefined) <span class="hljs-string">??</span> <span class="hljs-symbol">:<span class="hljs-string">"default value"</span></span>; <span class="hljs-regexp">//</span> <span class="hljs-string">'default value'</span> (undefined && (<span class="hljs-literal">false</span> |<span class="hljs-params"></span>| <span class="hljs-literal">true</span>)) <span class="hljs-string">??</span> <span class="hljs-string">"default value"</span>; <span class="hljs-regexp">//</span> <span class="hljs-string">'default value'</span> ((undefin

Options

ed && <span class="hljs-literal">false</span>) |<span class="hljs-params"></span>| <span class="hljs-literal">true</span>) <span class="hljs-string">??</span> <span class="hljs-string">"default value"</span>; <span class="hljs-regexp">//</span> <span class="hljs-literal">true</span></pre></div><h1 id="5d21">結論</h1><p id="19ae">過往在使用 Logical OR 和 Logical AND 實作 Short Circuit 機制時,其實已經相當方便,但在一些場景下,非常容易出錯,或是讓程式碼在判斷情境時更為麻煩。空值合併運算符(Nullish Coalescing Operator)將 Logical OR 在判定運算元(Operand )的條件限縮,讓我們在實作 Short Circuit 機制上更為方便。</p><p id="fb42">然而,使用上搭配 Logical OR 或 Logical AND 時,必須考量到運算子優先序的問題,因此必須透過括號明確去表明哪個運算子的位階較高,指名要先被執行——這其實也能提升程式碼的可讀性喔!</p><p id="1f28" type="7">最後,如果你喜歡這篇的分享,請不吝嗇的多點幾個 👏 給我超多鼓勵,感謝 :)</p><h1 id="51c4">參考資源</h1><div id="24a0" class="link-block"> <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Nullish_coalescing"> <div> <div> <h2>Nullish coalescing operator (??) - JavaScript | MDN</h2> <div><h3>The nullish coalescing operator can be seen as a special case of the logical OR (||) operator. The latter returns the…</h3></div> <div><p>developer.mozilla.org</p></div> </div> <div> <div style="background-image: url(https://miro.readmedium.com/v2/resize:fit:320/0*7fH0v8Vin0rWLA50)"></div> </div> </div> </a> </div><div id="11f0" class="link-block"> <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Operator_Precedence"> <div> <div> <h2>Operator precedence - JavaScript | MDN</h2> <div><h3>Consider an expression describable by the representation below, where both OP1 and OP2 are fill-in-the-blanks for…</h3></div> <div><p>developer.mozilla.org</p></div> </div> <div> <div style="background-image: url(https://miro.readmedium.com/v2/resize:fit:320/0*D3QPCl8ZQbu05KPs)"></div> </div> </div> </a> </div><div id="66e6" class="link-block"> <a href="https://javascript.info/nullish-coalescing-operator"> <div> <div> <h2>Nullish coalescing operator '??'</h2> <div><h3>The nullish coalescing operator is written as two question marks ??. As it treats null and undefined similarly, we'll…</h3></div> <div><p>javascript.info</p></div> </div> <div> <div style="background-image: url(https://miro.readmedium.com/v2/resize:fit:320/0*S_2SHmetpYP2nqmz)"></div> </div> </div> </a> </div><div id="fcbc" class="link-block"> <a href="https://www.educative.io/answers/what-is-the-nullish-coalescing-operator-in-javascript"> <div> <div> <h2>What is the nullish coalescing operator (??) in JavaScript?</h2> <div><h3>The nullish coalescing operator (??) returns the right-side value when its left-side value is null or undefined…</h3></div> <div><p>www.educative.io</p></div> </div> <div> <div style="background-image: url(https://miro.readmedium.com/v2/resize:fit:320/0*NDB3B2TCIXQizRPB)"></div> </div> </div> </a> </div><div id="5542" class="link-block"> <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Logical_OR"> <div> <div> <h2>Logical OR (||) - JavaScript | MDN</h2> <div><h3>The logical OR (||) (logical disjunction) operator for a set of operands is true if and only if one or more of its…</h3></div> <div><p>developer.mozilla.org</p></div> </div> <div> <div style="background-image: url(https://miro.readmedium.com/v2/resize:fit:320/0*FQAaEyqmh0X49Tss)"></div> </div> </div> </a> </div></article></body>

[筆記] JavaScript ES2020 空值合併運算符 Nullish Coalescing Operator (??)

在過去 Logical Operator(邏輯運算子) 讓開發者在撰寫程式碼時能夠更簡潔——其中最方便之處在於能讓我們能透過使用 ||&& 兩個邏輯運算子,像 if 般有條件的執行特定行為。這有鑒於 Logical Expression (邏輯運算式)的運作是由左到右執行,一旦第一個運算元(Operand)能夠滿足回傳的條件,就不會再繼續執行或評估第二個運算元——這樣的機制也被稱為「Short-circuit」。

即便如此,在特定場景中使用以上兩個邏輯運算子來使用 Short-circuit 的機制時,仍會遇到一些問題。因此,在 ECMAScript 2020 中推出了新的邏輯運算子:「空值合併運算符 Nullish Coalescing Operator」。

本篇將透過使用 Logical OR 介紹 Short-circuit 的運作機制和過往使用上會遇到的問題,緊接著介紹「空值合併運算符 Nullish Coalescing Operator」,以及如何適時的使用它,來解決過往的問題,並降低程式碼出錯的可能性。

Ligical OR(||)

Short-circuit 的機制不時會被用來取代 if…else… 的程式碼,而 Logical OR(||)是其中一個時常被使用的邏輯運算子。

舉下面範例來說,透過 Order() 函式能建立一筆筆訂單實例(instance),為了避免沒有帶入訂單資訊的情況,在函式內能透過 Logical OR 給定預設值——一旦第一個運算元回傳「Falsy」值,就會執行第二個運算元,藉以給定「預設值」。

下例在呼叫 Order() 函式時,由於未帶入第二個參數 size,因此 size 值為 undefined,而 undefined 為一個 Falsy 值,Logical OR 最終因而回傳第二個運算元:預設值 Medium

以往需要以 if…else…三元運算子(Ternary Operator)的寫法,現在能透過 Logical OR 更簡潔的達成:

❗️Falsy 值
JavaScript 當中的 Falsy 值包含 false, 0, -0, 空值 "", null, undefined, NaN 等。
在任何需要判斷 Boolean 值的上下文中(例如 if 或 while loop 等)帶入,將被轉成 false。

Ligical OR(||) 遇到的問題

Logical OR 看似好用,但也因為運作方式是「只要判定第一個運算元為 Falsy 值」就回傳後者(第二個運算元)。然而 Falsy 值的選項不只 nullundefined,還包含其他如 0 和空字串 “” 等,因此在某些情境下,誤使用 Logical OR 未必能發揮他的優勢,還反而造成反效果。

以下面範例來說,如果我們希望在使用者未選定是否要附袋子(isNeedBag)時,預設選擇要附上(true)、且如果使用者未輸入要多少糖包(sugarNum)時,預設都給予一包(1)。

然而在執行後能發現,無論 isNeedBag 被帶入什麼布林值,都會回傳 true;而由於 0 也是 Falsy 值,因此當使用者指定不需要糖包時,Logical OR 在判定後,仍會回傳預設值 1 包 — 這與原本預期的結果不同。

在這種情況下,工程師就需要再想其他方法來解決這個問題,例如把 isNeedBag 給定預設值的寫法改成下面的方式。然而,很多時候,反而會降低程式碼的可讀性,或變得不再簡潔了。

this.isNeedBag = arg.isNeedBag !== false;

這也是為什麼在 ECMA 2020 介紹了 Nullish coalescing operator (??)。

空值合併運算符 Nullish coalescing operator (??)

空值合併運算符(Nullish coalescing operator)和 Logical OR 的功能非常相似,但相比之下更為嚴謹:與其單純判斷是否為「Falsy」值,空值合併運算符判定是否為「Nullish」值——因此唯有當第一個運算元為「undefined」或「null」時,才會回傳第二個運算元。

如此一來,可以真實反映目標值是否未被給定或明確被給定為 undefinednull

回頭改寫訂單的範例,由於布林值 false 和數值 0 都不算 Nullish 值,因此 firstOrder.isNeedBagfirstOrder.sugarNum 在改寫後都能得到正確的回傳值。而由於訂單商品我們仍希望保有空字串的判斷,所以我們還是能繼續使用 Logical OR,因此 firstOrder.item 最終被給予預設值 Tea

使用上的注意事項

在 JavaScirpt 中有各種運算子(Operator),而理論上要在一個運算式(Expression)使用多個運算子是沒有問題的。然而,當一個運算式中包含了多個運算子時,就會遇到「哪個運算子該先被執行」。

這其實就跟以下呈現的加減乘除一樣,由於我們人類知道「先乘除後加減」的規則,因此我們會先執行 3 * 2,再將結果 6 拿去執行 6 + 1,最終獲得 7。然而,電腦沒有這方面的知識,因此如果照著由左至右一一執行,最終將得到 8 這個答案:

1 + 3 * 2 // 7

運算子優先序(Operator precedence)

JavaScript 將運算子歸類成不同的位階,以此來決定執行的順序:運算子優先序。從位階表中能發現乘除法比加減法位階來得高,因此電腦在這方面的計算也能得出正確的答案。

邏輯運算子中 Logical AND (&&)的位階則高於 Logical OR(||),因此當一個運算式中(如下範例)同時運用了 Logical AND 和 LogicalOR,前者將優先被執行。然而,如果希望範例中的 Ligical OR 先被執行,則可以使用位階更高的 GroupingOperator () 來達成效果。

false && false || true // true
false && (false || true) // false

空值合併運算符(Nullish Coalescing Operator)的位階和 Logical OR 相同,但比 Logical AND 還來得低。若將空值運算符與另外兩個運算符「直接串接在一起合併使用」非常容易出現預期外的結果,因此是「不被允許」的,你會看到語法錯誤的訊息:

false || undefined ?? "default value"; // Uncaught Syntax Error:Unexpected token '??'

相反的,使用上開發者必須使用括號 () 明確的指定優先序:

(false || undefined) ?? :"default value"; // 'default value'
(undefined && (false || true)) ?? "default value"; // 'default value'
((undefined && false) || true) ?? "default value"; // true

結論

過往在使用 Logical OR 和 Logical AND 實作 Short Circuit 機制時,其實已經相當方便,但在一些場景下,非常容易出錯,或是讓程式碼在判斷情境時更為麻煩。空值合併運算符(Nullish Coalescing Operator)將 Logical OR 在判定運算元(Operand )的條件限縮,讓我們在實作 Short Circuit 機制上更為方便。

然而,使用上搭配 Logical OR 或 Logical AND 時,必須考量到運算子優先序的問題,因此必須透過括號明確去表明哪個運算子的位階較高,指名要先被執行——這其實也能提升程式碼的可讀性喔!

最後,如果你喜歡這篇的分享,請不吝嗇的多點幾個 👏 給我超多鼓勵,感謝 :)

參考資源

JavaScript
Frontend Development
Notes
Es2020
Ecmascript 2020
Recommended from ReadMedium