Logo

新人日誌

首頁關於我部落格

新人日誌

Logo

網站會不定期發佈技術筆記、職場心得相關的內容,歡迎關注本站!

網站
首頁關於我部落格
部落格
分類系列文

© 新人日誌. All rights reserved. 2020-present.

本文為「JS 101:資料型別」系列第 11 篇

JavaScript 短路邏輯運算子:用 || 和 && 寫出更簡潔的程式碼

最後更新:2026年3月4日JavaScript

你可能已經知道 ||(OR)和 &&(AND)是邏輯運算子,用來處理布林值的判斷。

但你知道嗎?在 JavaScript 裡,這兩個運算子其實不只是回傳 true 或 false,它們還會根據一套特殊規則,決定要回傳左邊還是右邊的值。

這篇文章會帶你搞懂這套規則,並且學會一個叫做「短路評估」的重要特性。

|| 運算子:找到第一個「有東西的」值

|| 是邏輯上的「或」,最基本的用法是這樣的:只要左右兩邊有任何一邊是 true,結果就是 true。

console.log(true || false);
// → true

console.log(false || false);
// → false

這是它在布林值之間的標準行為,應該蠻好理解的。

但在 JavaScript 裡,|| 其實不只能處理布林值,它也可以接受其他型態的值,像是字串、數字、null 等等。

而且,它回傳的結果也不一定是 true 或 false。

事實上,|| 和 && 在 JavaScript 底層的設計中,從來就不是為了「比較出一個布林值」而存在的。

它們做的事情是:看看左右兩邊的值,決定要回傳哪一邊,然後把選中的值原封不動地丟回來。

所以當兩邊都是布林值,回傳的自然就是布林值。

但如果兩邊放的是字串、數字、null 這些東西,它一樣會選一邊回傳,而回傳的就會是那個字串、數字或 null。

那 || 碰到非布林值時,到底會怎麼做?直接來看例子比較清楚:

console.log(null || "user");
// → "user"

null 是空的,沒有東西,所以 || 跳過它,回傳右邊的 "user"。

console.log("Agnes" || "user");
// → "Agnes"

"Agnes" 是一個有內容的字串,|| 覺得它是有效的值,就直接回傳它,右邊的 "user" 根本不會被用到。

看出規律了嗎?|| 會看左邊的值是不是「有東西」,如果有,就回傳左邊;如果左邊是空的、沒意義的值,就回傳右邊。

哪些值算是「空的、沒意義的」?

在 JavaScript 裡,以下這些值會被當成「空的」(通常稱為 falsy 值):

  • 0
  • NaN
  • ""(空字串)
  • null
  • undefined

除了上面這些之外,其他所有值都算是「有東西的」(稱為 truthy 值)。

來看看實際的效果:

console.log(0 || -1);
// → -1

0 是 falsy,|| 覺得它是空的,所以回傳右邊的 -1。

console.log("" || "!?");
// → "!?"

空字串 "" 也是 falsy,所以回傳右邊的 "!?"。

那如果兩邊都是「空的」呢?

console.log(null || "");
// → ""

null 是 falsy,所以 || 跳過左邊,回傳右邊的 ""。

即使右邊也是 falsy,|| 還是會把它回傳,因為它已經沒得選了。

用 || 設定預設值

理解了 || 的運作方式之後,我們可以拿它來做一件很實用的事:設定預設值。

假設你在寫一個程式,使用者可能有輸入名字,也可能沒有輸入。

如果沒有輸入,你希望顯示「訪客」作為替代,這時候就可以用 ||:

console.log(null || "訪客");
// → "訪客"

左邊是 null(falsy),所以 || 回傳右邊的 "訪客"。

但如果使用者有輸入名字的話:

console.log("小明" || "訪客");
// → "小明"

"小明" 是 truthy,所以 || 直接回傳左邊的值,右邊的 "訪客" 不會被用到。

這就是所謂的「預設值」技巧:把可能是空的東西放在 || 左邊,把替代值放在右邊。

這個技巧在實際開發中非常常見,可以讓你的程式碼更簡潔。

不過這裡有一個要小心的地方。

|| 沒辦法區分「真的沒有值」和「值剛好是 0 或空字串」。

先看正常的情況,使用者沒有輸入,左邊是 null:

console.log(null || 10);
// → 10

沒問題,null 是 falsy,|| 回傳右邊的預設值 10。

但如果使用者剛好輸入了 0:

console.log(0 || 10);
// → 10

0 也是 falsy,所以被跳過了,回傳了 10。

使用者明明有輸入 0,而且 0 是一個有效的數字,但因為在 JavaScript 裡 0 是 falsy,所以被 || 誤判成「沒有輸入」而跳過了。

這就是用 || 設定預設值的陷阱。

&& 運算子:找到第一個「空的」值

理解了 || 之後,&& 就簡單了,因為它的邏輯剛好相反。

|| 是從左往右找第一個「有東西的」值,而 && 是從左往右找第一個「空的」值。

只要左邊碰到一個 falsy 的值,&& 就覺得「走不下去了」,立刻停下來,把這個擋住它的值回傳給你。

如果左邊是 truthy 的,它就繼續往右走,回傳右邊的值。

來看個例子:

console.log(null && "hello");
// → null

null 是 falsy,所以 && 直接回傳左邊的 null,右邊的 "hello" 完全不會被處理。

console.log("hi" && "hello");
// → "hello"

"hi" 是 truthy,所以 && 回傳右邊的 "hello"。

在實際開發中,&& 有一個很常見的用法:安全檢查。

意思是先用 && 確認左邊不是空的,才去執行右邊的操作,避免程式因為碰到空值而當掉。

這個用法要搭配後面會學到的變數和物件才比較好理解,到時候你會很常看到它。

短路評估:右邊的程式碼根本不會執行

前面我們一直在講 || 和 && 會「回傳哪一邊的值」。

但其實還有一件事值得特別拿出來說:當左邊就能決定結果時,右邊的程式碼根本不會被執行。

不是「執行了但不回傳」,而是「完全不會去碰它」。

這有什麼差別?先回憶一下前面講的規則:

|| 是找第一個「有東西的」值:左邊有東西就回傳左邊,左邊是空的才去看右邊。

&& 是找第一個「空的」值:左邊是空的就回傳左邊,左邊有東西才去看右邊。

關鍵在於:如果左邊就能決定結果,|| 和 && 連看都不會去看右邊。

來看一個例子:

console.log(true || console.log("我被執行了"));
// → true

左邊是 true(truthy),對 || 來說已經找到「有東西的」值了,不需要再看右邊。

所以右邊的 console.log("我被執行了") 完全沒有執行,畫面上不會出現「我被執行了」這段文字。

&& 也是一樣的道理:

console.log(false && console.log("我被執行了"));
// → false

左邊是 false(falsy),對 && 來說已經找到「空的」值了,不需要再看右邊,右邊完全被跳過。

這個特性就叫做短路評估(short-circuit evaluation)。

為什麼這很重要?因為這代表右邊可以放一些「可能會出錯的操作」。

只要左邊就能決定結果,右邊就完全不會被執行,程式也不會因此當掉。

前面 && 安全檢查的用法,其實就是靠短路評估才能成立的。

那為什麼叫「短路」?

在電力學中,「短路」是指電流不經過原本該去的電器,而是走了一條更短、電阻更小的捷徑直接回到電源。

在程式設計中,這個術語借用了同樣的邏輯:「提早結束,不走完全程。」

正常來說,A && B 或 A || B 應該要把 A 和 B 兩邊都看過才對。

但短路機制讓程式可以「偷懶」:如果看完左邊就已經知道結果了,右邊就直接跳過,不浪費力氣去執行它。

條件運算子也有類似行為

條件運算子(? :)也有同樣的特性:

console.log(true ? "A" : "B");
// → "A"

條件是 true,所以只有 "A" 會被評估,"B" 完全不會被碰到。

反過來也是:

console.log(false ? "A" : "B");
// → "B"

條件是 false,所以 "A" 不會被碰到,只有 "B" 會被評估。

不管是 ||、&& 還是 ? :,都遵守同一個原則:已經能決定結果了,就不會再去碰多餘的部分。

當 && 和 || 同時出現:優先順序

前面的例子都只有一個 || 或一個 &&,但如果它們同時出現在同一行呢?

console.log("" && "World" || "Goodbye");

這時候 JavaScript 要怎麼決定先算哪個?

跟數學裡「先乘除,後加減」一樣,&& 的優先順序比 || 高。

所以 JavaScript 會先幫你「分組」,把 && 的部分括起來:

console.log(("" && "World") || "Goodbye");

我們一步一步來:

第一步,先算 "" && "World"。

還記得嗎?&& 是找第一個「空的」值。"" 是空字串,是 falsy,&& 找到了,直接回傳左邊的 ""。

現在變成:"" || "Goodbye"。

第二步,換 || 上場。|| 是找第一個「有東西的」值。"" 還是 falsy,不算有東西,所以 || 跳過它,回傳右邊的 "Goodbye"。

console.log("" && "World" || "Goodbye");
// → "Goodbye"

再來看另一個例子:

console.log("Hi" || 0 && "Bye");

一樣,&& 優先,所以 JavaScript 看到的是:

console.log("Hi" || (0 && "Bye"));

但這次的情況不一樣,會顛覆你剛剛建立的直覺。

優先順序把它分組成 "Hi" || (0 && "Bye")。

照前面的邏輯,你可能以為要先算括號裡的 0 && "Bye"。

但其實不是這樣的。優先順序決定的只是「怎麼分組」,實際執行的時候,JavaScript 還是從左到右看的。

JavaScript 從左邊開始,先碰到 ||,然後看 || 的左邊:"Hi" 是 truthy。|| 是找第一個「有東西的」值,"Hi" 就是,任務完成,直接回傳 "Hi"。

因為短路評估,|| 已經決定結果了,右邊的 (0 && "Bye") 根本不會被執行。

console.log("Hi" || 0 && "Bye");
// → "Hi"

那回頭看第一個例子:

console.log(("" && "World") || "Goodbye");

JavaScript 從左到右看,先碰到 ||,要決定回傳左邊還是右邊。

但 || 的左邊不是一個單純的值,而是 "" && "World" 這個表達式。

所以 JavaScript 要先把它算完,才能知道 || 左邊到底是什麼:

"" && "World"  // → ""

算完之後,現在變成:

"" || "Goodbye"  // → "Goodbye"

所以 && 不是因為優先順序高就「搶先執行」,而是因為它剛好在 || 的左邊,JavaScript 從左到右走的時候自然會先碰到它。

所以:優先順序決定怎麼分組,執行順序還是從左到右,搭配短路評估決定哪些部分會被跳過。

優先順序執行順序
決定什麼?怎麼分組(加括號)實際從哪邊開始算
類比數學的「先乘除,後加減」數學的「從左算到右」
規則&& 比 || 高一律從左到右
優先順序怎麼分組(加括號)
執行順序實際從哪邊開始算
優先順序數學的「先乘除,後加減」
執行順序數學的「從左算到右」
優先順序&& 比 || 高
執行順序一律從左到右

小結

  • || 和 && 不是只能回傳布林值,它們會把選中的那一邊原封不動地回傳。
  • || 從左往右找第一個 truthy(有東西的)值;如果都找不到,就回傳最後一個值。
  • && 從左往右找第一個 falsy(空的)值;如果都找不到,就回傳最後一個值。
  • 0、NaN、""、null、undefined 這些值都是 falsy。
  • || 常被用來設定預設值;&& 常被用來做安全檢查。
  • && 的優先順序比 || 高,但優先順序只決定怎麼分組,實際執行還是從左到右,搭配短路評估決定哪些部分被跳過。
  • 短路評估代表只要左邊就能決定結果,右邊就不會被執行。
  • 條件運算子(? :)也有類似的短路行為。
上一篇JavaScript 自動轉換型態( Type Coercion)與比較運算子完整解析
下一篇JavaScript 運算子全解:一元、二元、三元運算子一次搞懂!
目前還沒有留言,成為第一個留言的人吧!

發表留言

留言將在審核後顯示。

JavaScript

目錄

  • || 運算子:找到第一個「有東西的」值
  • 哪些值算是「空的、沒意義的」?
  • 用 || 設定預設值
  • && 運算子:找到第一個「空的」值
  • 短路評估:右邊的程式碼根本不會執行
  • 條件運算子也有類似行為
  • 當 && 和 || 同時出現:優先順序
  • 小結