写程式时该用三元运算子 (ternary operator) 吗?

2024年5月27日

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

前阵子看到一个在讨论三元运算子 (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 上追蹤我們