谨慎使用if

122 阅读4分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第31天,点击查看活动详情

除非绝对必要,否则停止使用 if 语句。

在绝大数的情况下,我们应该尽可能的避免使用if,因为if是一种相对笨拙的代码编写方式。

别误会我的意思,在一定前提下,if语句在某些情况下是很有用的。但是,在可以避免的地方如果过于使用他们,不 不仅会使我们在几个月后重新来看代码的时候变得更加困难,同样还会影响开发人员理解上下文,需要花费跟多的时间来理解,这多少有点得不偿失。编码并继续分配给他们的任务。这会扰乱“流动”并导致整体效率降低,从而积少成多。

首先,我们来查看下面的代码片段,我们通过加密的卡号从数据库中检索卡,并根据特定条件返回验证响应。

async validateCard(encryptedCardNumber) {
  const card = await this.lookupCard(encryptedCardNumber);
  if (!card) {
    console.log(NotFoundResponse.message);
    return NotFoundResponse;
  }
  else if (card.isBlacklisted) {
    console.log(BlacklistedReponse.message);
    return BlacklistedResponse;
  }
  else if (card.isDeleted) {
    console.log(DeletedResponse.message);
    return DeletedResponse;
  } 
  else if (card.status !== CardStatus.active) {
    console.log(InactiveResponse.message);
    return InactiveResponse;
  }
  else {
    console.log(ValidResponse.message);
    return ValidResponse;
  }
}

拥有这么多if陈述不仅需要花费相当多的精力来理解,而且随着更多条件的增加,我们很快就会上下滚动以确保每个案例都得到满足,从而越加越多。因此,为了可维护性我们需要提取重复的代码。

接下来的示例就是这样做的。它用逻辑 AND和Logical_OR替换了无数的 if 语句,这更简洁,让人更容易理解。对于那些不熟悉析取和合取的人,我强烈建议都去查一下,学习一下,我这里做一个简单简短的描述:

  • 逻辑 AND ( &&) 从左到右计算操作数,立即返回它遇到的第一个假操作数的值;果所有值都是真值,则返回最后一个操作数的值。
  • 当且仅当其一个或多个操作数为真时,一组操作数的逻辑 OR ( ||) 运算符(逻辑析取)为真。使用短路求值,它只返回第一个真值表达式。

回到上面说的,我们继续看看提取重复代码后的例子:

async validateCard(encryptedCardNumber) {
  const card = await this.lookupCard(encryptedCardNumber);
  
  const response = 
    !card && NotFoundResponse ||
    card.isDeleted && DeletedResponse || 
    card.isBlacklisted && BlacklistedResponse ||
    card.status !== cardStatus.active && InvalidStatus ||
    ValidResponse;

  console.log(response.message);
  return response;
}

随着业务需求的变化,代码也会发生变化。在某些情况下可能会完全删除代码,但在其他情况下,它会扩展到已经存在的内容。这也会是一个很受欢迎的面试问题,它与创建可扩展解决方案的能力有关

接下来我们来继续查看几个例子:

创建一个函数,将 1-10 之间的给定数字转换为单词

很简单吧?只需在函数中添加一堆 if(或 switch)语句就可以了,并给面试官留下深刻印象。

function convertIntegerToText(num) {
  if (num === 1) return "one";
  if (num === 2) return "two";
  if (num === 3) return "three";
  // ...
  if (num === 10) return "ten";
}

10个跟简单,但是如果是100 1000 甚至10000呢?

现在你要怎么办?

继续为每个场景编写 if 语句?10000个if要写多少张草稿纸,花费多少个小时?

更好的方法是从一开始就考虑可扩展的解决方案。在设计、架构、编写和维护代码时要牢记的一个关键基本原则是时间如何影响软件的可持续性以及如何使您的代码随着时间的推移具有弹性。

因此,一个可扩展的解决方案是一个代码,其中没有任何if语句或几个语句可以覆盖大多数情况,只需最少或不需要修改。就像下面这个例子:

const ONES = ["", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine"];
const TEENS = ["ten", "eleven", "twelve", "thirteen", "fourteen", "fifteen", "sixteen", "seventeen", "eighteen", "nineteen"];
const TENS = ["", "", "twenty", "thirty", "fourty", "fifty", "sixty", "seventy", "eighty", "ninety"];

function convertIntegerToText(num) {
  if (num < 20) 
    return ONES[num] ?? TEENS[num - 10];
  
  if (num < 100)
    return `${TENS[Math.floor(num / 10)]} ${convertIntegerToText(num % 10)}`;
  
  if (num < 1000)
    return `${ONES[Math.floor(num / 100)]} hundred ${convertIntegerToText(num % 100)}`;
  
  throw new Error("Number too high");
}

最后,让我们来看看下面这段代码片段,并自行判断你认为哪一个具有高度可扩展性、可维护性、更易于阅读,并且如果你遇到它会如何帮助到你?

// home.jsx
function getCompanyTemplate(company) {
  if (company === "apple") {
    return <AppleTemplate />
  }
  if (company === "samsung") {
    return <SamsungTemplate />
  }
  if (company === "sony") {
    return <Sony />
  }
  if (company === "lg") {
    return <Lg />
  }
}
  
// OR
  
// index.jsx
export const templates = {
  apple: <Apple />,
  samsung: <Samsung />,
  sony: <Sony />,
  lg: <Lg />,
}

// home.jsx
import { templates } from "./index"
function getCompanyTemplate(company) {
  return templates[company];
}