寫程式時該用三元運算子 (ternary operator) 嗎?

2024年5月27日

💎 加入 E+ 成長計畫 與超過 400+ 位軟體工程師一同在社群中成長,並且獲得更多的軟體工程學習資源

前陣子看到一個在討論三元運算子 (ternary operator) 的討論串,覺得蠻有趣的。因此在這期雙週報,來跟大家談這個運算子。以前端開發來說,三元運算子是蠻常用到的,但社群的人對使用三元運算子有不同的觀點。

先來看看 MDN 上怎麼定義三元運算子,MDN 的定義是「運算子是 JavaScript 唯一用到三個運算元的運算子:在一個條件後面會跟著一個問號(?),如果條件是 truthy,在冒號(:)前的表達式會被執行,如果條件是 falsy ,在冒號後面的表達式會被執行,這個運算子常常被用來當作if的簡潔寫法」。

舉個具體的例子,如果今天有一個 getFee 函式,會根據是不是會員,來回傳不同的價格。如果是會員,則需要 $2 塊錢,不是會員則需要 $10 塊錢。我們可以簡單地寫成:

function getFee(isMember) {
  if (isMember) {
    return "$2.00";
  } else {
    return "$10.00";
  }
}

如果用三元運算子,則可以變成這樣,原本四行的程式碼,被一行簡化:

function getFee(isMember) {
  return isMember ? "$2.00" : "$10.00";
}

雖說上面的例子,三元運算子看起來比較簡潔,但在一些不同的情況下,三元運算子反而會讓可讀性變差,這也是為什麼 ESLint 當中甚至有條 no-nested-ternary ,禁止下面這種看過去讓人沒辦法一眼看懂的程式碼:

foo ? (baz === qux ? quxx() : foobar()) : bar();

三元運算子究竟好不好用,其實很主觀。舉例來說,有人認為三元運算子會比用 && 來的好,舉例來說,下面這種狀況,是在寫前端 JSX 元件很常會出現的問題,因為 members.length 如果是 0 的話, 0 && 某個東西 結果會直接渲染 0

<div>
  {members.length &&
    members.map((member) => <div key={member.id}> {member.name} </div>)}
</div>

因此有些人會認為,這時候用三元運算子比較好 (例如下面這樣)。但有人則認為三元運算子的可讀性會比較差,所以認為與其用三元運算子,不如確定 && 前面會是布林值,例如檢查 members.length > 0 而不是檢查 members.length

<div>
  {members.length
    ? members.map((member) => <div key={member.id}> {member.name} </div>)
    : null}
</div>

另外則有人說,與其用三元運算子,不如把這個抽成元件,然後在元件中引用,這樣的可讀性又更高一點。

function MemberList({ members }: MemberListProps) {
  if (members.length === 0) {
    return null;
  }

  return (
    <div>
      {members.map((member) => (
        <div key={member.id}> {member.name} </div>
      ))}
    </div>
  );
}

不只在 JavaScript 中,三元運算子有爭議;在其他的程式語言中,三元運算子也有被大量討論過。JavaScript 的三元運算子語法是跟 C 比較類似的,是由 ?: 所組成。

然而這種設計,有時看起來過於抽象,難以讓人一眼看懂,所以在其他的語言中,會看到不同的設計方式。舉例來說,Python 是把 if...else 直接化為一行的形式 '$2.00' if isMember else '$10.00'。而 Go 語言則直接表示,因為三元運算子容易造成難以閱讀的程式碼,所以決定不支援這種語法。

總的來說,程式碼是種表達與溝通的工具,三元運算子雖然在某些狀況比較簡潔,但確實有時反而會導致程式碼比較難閱讀。回過頭來說,一個工具的使用,還是端看使用的人怎麼用;不要教條式的認為三元運算子比較簡潔,或者比較難閱讀,而是要看情況,在適合的情況使用,達到最好的效果。

🧵 如果你想收到最即時的內容更新,可以在 FacebookInstagram 上追蹤我們