美文网首页
停止在 JavaScript 中嵌套三元组

停止在 JavaScript 中嵌套三元组

作者: 涅槃快乐是金 | 来源:发表于2024-03-15 21:04 被阅读0次

    Prettier,最受欢迎的JavaScript代码格式化工具,最近发布了一种新颖的方法来格式化嵌套的三元表达式。

    我对如何使嵌套的三元表达式更清晰有更好的想法:停止嵌套它们。

    嵌套三元表达式是什么意思?

    三元运算符是基于条件进行决策的if/else的替代方法。常规的三元表达式看起来像:

    const animalName = pet.canBark() ? "dog" : "cat";
    

    嵌套的三元表达式是在真或假分支中进一步输入三元表达式的情况。

    const animalName =
      pet.canBark() ?
        pet.isScary() ?
          'wolf'
        : 'dog'
      : pet.canMeow() ? 'cat'
      : 'probably a bunny';
    

    让我们看看为什么这不是一个好的实践。

    为什么嵌套的三元表达式不好

    代码应该清晰而直接。嵌套的三元表达式很少清晰或直接;我个人发现它们比其他形式的条件语句更难阅读和理解。

    我们阅读代码的次数比编写代码多得多,所以代码在头脑中解析起来应该尽可能简单。通过问号和冒号来确定表达式的含义要比阅读明确说明的if/else语句不清晰得多。

    Sonar也不认为嵌套的三元表达式清晰而直接。SonarQubeSonarCloudSonarLint都强制执行三元运算符不应嵌套的规则作为Sonar way配置文件的一部分。

    更清晰的方式

    那么,我们用什么来替代嵌套的三元表达式呢?让我们用几种不同的方式来重写Prettier示例中的嵌套三元表达式。他们的示例代码,按照新的格式,是这样的:

    const animalName =
      pet.canBark() ?
        pet.isScary() ?
          'wolf'
        : 'dog'
      : pet.canMeow() ? 'cat'
      : 'probably a bunny';
    
    嵌套条件语句

    用条件语句来替代嵌套的三元表达式最简单的方式是将它们转换为条件语句:

    let animalName = 'probably a bunny';
    if (pet.canBark()) {
      if (pet.isScary()) {
        animalName = 'wolf';
      } else {
        animalName = 'dog';
      }
    } else if (pet.canMeow()) {
      animalName = 'cat';
    }
    

    在这个例子中,我们设置了一个变量,在条件语句中将其赋值。我们可以用其默认值开始这个变量,省略了一个else子句。然后,我们应用与原始示例相同的逻辑,但使用if/else块。

    一些开发人员对这种风格的问题之一是使用了let变量。三元运算符的好处在于它是一个表达式;也就是说,它返回一个值。而if/else语句不返回任何东西,你需要改变一个变量或者使用return

    如果使用变量感觉不对劲,你可以将语句重构成自己的函数并使用早期返回。

    function animalName(pet) {
      if (pet.canBark()) {
        if (pet.isScary()) {
          return "wolf";
        }
        return "dog";
      } else if (pet.canMeow()) {
        return "cat";
      }
      return "probably a bunny";
    }
    

    当你将行为重构成自己的函数时,你可以独立测试功能,确保它是正确的,并且不能被无意中破坏。你可以省略额外的变量赋值。

    减少嵌套

    代码中真正的问题在于嵌套本身。嵌套是使代码更加复杂的一个特性。

    在这个例子中,我们可以重构嵌套以使得这个函数更容易理解:

    function animalName(pet) {
      if (pet.canBark() && pet.isScary()) { return "wolf"; }
      if (pet.canBark()) return "dog";
      if (pet.canMeow()) return "cat";
      return "probably a bunny";
    }
    

    现在,这个函数比我们开始时的嵌套三元表达式更清晰,并且使用的行数更少。

    我喜欢这是一个单独的函数,你可以为它编写测试。但如果将此行为包含在其原始位置中对你很重要,你可以将其作为立即调用的函数表达式(IIFE)实现:

    const animalName = (() => {
      if (pet.canBark() && pet.isScary()) { return "wolf"; }
      if (pet.canBark()) return "dog";
      if (pet.canMeow()) return "cat";
      return "probably a bunny";
    })();
    

    就我个人而言,我喜欢将代码提取到单独的函数中,原因如上所述,而且我认为IIFE会增加额外的混乱。你可能有不同的看法,如果是这样,IIFE是一个选项。

    赞成嵌套三元表达式?

    支持嵌套三元表达式,并将其称为“链式三元表达式”,一旦你对条件进行操作,确保只在三元表达式的else子句中进行链式操作。关于语句和表达式之间的区别的观点是正确的,我们应该尽量避免副作用和变异,而表达式可以实现这一点。

    第一个论点是,if/else语句允许您编写引起副作用的代码。然而,一旦您将条件降低为可以写为嵌套三元表达式的代码,您也可以通过将其重写为具有返回的函数来避免副作用和变异,就像我们上面所做的那样。另一方面,您绝对可以在三元表达式中编写突变和副作用,所以对我来说,这似乎是一个无关紧要的观点。

    第二个论点是,if/else语句的语法是一种占用工作内存的混乱,会引起干扰,并留下更大的错误表面积。对我来说,解析三元表达式需要我在脑海中构思语法,所以即使文件中没有“if”“else”,我的对三元表达式的理解也需要。将ifelse改为问号和冒号的想法使得代码的错误表面积更小一些对我来说有点牵强。我不会争论使用if/else语句会帮助你编写更正确的代码,也不认同使用更少的字符会实现这一点。我主张使用if/else语句可以使代码更清晰、更容易理解。对我个人而言,理解和转换三元语法的工作实际上增加了我在维护过程中引入错误的可能性。

    嵌套三元表达式有用的地方吗?

    使用JSX的人可能已经感到愤怒了。

    JSX中没有if/else语句,所以您需要使用三元运算符来做出决策。然后,在渲染组件时,将这些操作嵌套是很常见的,并且在代码中包括条件属性,例如:

    return (
      <>
        {isLoading ? (
          <Loader active />
        ) : (
          <Panel label={isEditing ? 'Open' : 'Not open'}>
            <a>{isEditing ? 'Close now' : 'Start now'}</a>
            <Checkbox onClick={!saving ? setSaving(saving => !saving) : null} />
          </Panel>
        )}
      </>
    );
    

    当然,在JSX中需要嵌套的三元表达式,所以上面的代码是完全合理的。我的建议仍然是尽量减少嵌套。值得注意的是,嵌套三元表达式的Sonar规则不适用于JSX

    减少嵌套,优先清晰而不是简洁

    在代码中进行嵌套会引入复杂性,所以当你发现自己使用嵌套三元表达式时,首先要做的是尽量重构以尽量减少嵌套。然后,您可以使用上面的任何模式来删除嵌套的三元表达式。

    关于上面的任何替代方案,您可以说的一件事是它们都使用更多的字符,涉及更多的键入工作比基于三元表达式的解决方案。然而,正如我之前所断言的,代码通常被阅读的次数远远超过被编写的次数。

    当你在编写代码时有意识地选择最小化嵌套并使用更少的三元运算符时,你会发现你的代码随着时间的推移变得更加清晰和易于理解和修改。

    相关文章

      网友评论

          本文标题:停止在 JavaScript 中嵌套三元组

          本文链接:https://www.haomeiwen.com/subject/tlggzdtx.html