Javascript 替代 JS 中的嵌套三元运算符

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/32289340/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-23 07:50:54  来源:igfitidea点击:

Alternative to nested ternary operator in JS

javascriptternary-operatoreslint

提问by dthree

I personally love ternary operators, and in my humble opinion, they make complicated expressions very easy to digest. Take this one:

我个人喜欢三元运算符,在我看来,它们使复杂的表达式很容易理解。拿这个:

  word = (res.distance === 0) ? 'a'
    : (res.distance === 1 && res.difference > 3) ? 'b'
    : (res.distance === 2 && res.difference > 5 && String(res.key).length > 5) ? 'c'
    : 'd';

However in our project's ESLINT rules nested ternary operators are forbidden, so I have to get rid of the above.

但是在我们项目的 ESLINT 规则中,嵌套的三元运算符是被禁止的,所以我必须摆脱上面的内容。

I'm trying to find out alternatives to this approach. I really don't want to turn it into a huge if / else statement, but don't know if there's any other options.

我正在尝试找出这种方法的替代方法。我真的不想把它变成一个巨大的 if / else 语句,但不知道是否还有其他选择。

采纳答案by T.J. Crowder

Your alternatives here are basically:

您在这里的选择基本上是:

  1. That if/elseyou don't want to do
  2. A switchcombined with if/else
  1. 那个if/else你不想做的
  2. Aswitch结合if/else

I tried to come up with a reasonable lookup map option, but it got unreasonable fairly quickly.

我试图想出一个合理的查找地图选项,但很快就变得不合理了。

I'd go for #1, it's not that big:

我会去#1,它不是那么大:

if (res.distance == 0) {
    word = 'a';
} else if (res.distance == 1 && res.difference > 3) {
    word = 'b';
} else if (res.distance == 2 && res.difference > 5 && String(res.key).length > 5) {
    word = 'c';
} else {
    word = 'd';
}

If all the braces and vertical size bother you, without them it's almost as concise as the conditional operator version:

如果所有的大括号和垂直大小都困扰你,没有它们,它几乎和条件运算符版本一样简洁:

if (res.distance == 0) word = 'a';
else if (res.distance == 1 && res.difference > 3) word = 'b';
else if (res.distance == 2 && res.difference > 5 && String(res.key).length > 5) word = 'c';
else word = 'd';

(I'm not advocating that, I never advocate leaving off braces or putting the statement following an ifon the same line, but others have different style perspectives.)

(我不提倡这样做,我从不提倡去掉大括号或将语句if放在同一行之后,但其他人有不同的风格观点。)

#2 is, to my mind, more clunky but that's probably more a style comment than anything else:

#2 在我看来,更笨重,但这可能比其他任何东西都更像是一种风格评论:

word = 'd';
switch (res.distance) {
    case 0:
        word = 'a';
        break;
    case 1:
        if (res.difference > 3) {
            word = 'b';
        }
        break;
    case 2:
        if (res.difference > 5 && String(res.key).length > 5) {
            word = 'c';
        }
        break;
}


And finally, and I am notadvocating this, you can take advantage of the fact that JavaScript's switchis unusual in the B-syntax language family: The casestatements can be expressions, and are matched against the switch value in source code order:

最后,我提倡这一点,您可以利用 JavaScriptswitchB语法语言家族中不寻常的事实:case语句可以是表达式,并按源代码顺序与 switch 值匹配:

switch (true) {
    case res.distance == 0:
        word = 'a';
        break;
    case res.distance == 1 && res.difference > 3:
        word = 'b';
        break;
    case res.distance == 2 && res.difference > 5 && String(res.key).length > 5:
        word = 'c';
        break;
    default:
        word = 'd';
        break;
}

How ugly is that? :-)

那有多丑?:-)

回答by Andrey Mikhaylov - lolmaus

To my taste, a carefully structured nested ternary beats all those messy ifs and switches:

在我看来,一个精心构造的嵌套三元组胜过所有那些凌乱的 if 和 switch:

const isFoo = res.distance === 0;
const isBar = res.distance === 1 && res.difference > 3;
const isBaz = res.distance === 2 && res.difference > 5 && String(res.key).length > 5;

const word =
  isFoo ? 'a' :
  isBar ? 'b' :
  isBaz ? 'c' :
          'd' ;

回答by Yo Wakita

You could write an immediately invoked function expressionto make it a little more readable:

您可以编写一个立即调用的函数表达式,使其更具可读性:

const word = (() =>  {
  if (res.distance === 0) return 'a';
  if (res.distance === 1 && res.difference > 3) return 'b';
  if (res.distance === 2 && res.difference > 5 && String(res.key).length > 5) return 'c';
  return 'd';
})();

Link to repl

链接到repl

回答by dhaker

We can simplify it using basic operators like && and ||

我们可以使用像 && 和 || 这样的基本运算符来简化它

let obj = {}

function checkWord (res) {
      return (res.distance === 0)   && 'a'
             || (res.distance === 1 && res.difference > 3) && 'b' 
             || (res.distance === 2 && res.difference > 5  && String(res.key).length > 5) && 'c'
             || 'd';
           
}

// case 1 pass
obj.distance = 0
console.log(checkWord(obj))

// case 2 pass
obj.distance = 1
obj.difference = 4
console.log(checkWord(obj))

// case 3 pass
obj.distance = 2
obj.difference = 6
obj.key = [1,2,3,4,5,6]
console.log(checkWord(obj))

// case 4 fail all cases
obj.distance = -1
console.log(checkWord(obj))

回答by K McCabe

word = (res.distance === 0) ? 'a'
: (res.distance === 1 && res.difference > 3) ? 'b'
: (res.distance === 2 && res.difference > 5 && String(res.key).length > 5) ? 'c'
: 'd';

This is an older question, but this is how I would do it... I would start with the default case and then change the variable or pass it unchanged as desired.

这是一个较旧的问题,但这就是我将如何做到的......我会从默认情况开始,然后更改变量或根据需要将其传递不变。

var word = 'd';
word = (res.distance === 0) ? 'a' : word;
word = (res.distance === 1 && res.difference > 3) ? 'b' : word
word = (res.distance === 2 && res.difference > 5 && String(res.key).length > 5) ? 'c' : word;

回答by Amit

If all your truthy conditions evaluate to truthy values (so the value between the question mark and the semicolon evaluates to true if coerced to boolean...) you could make your ternary expressions return falseas the falsy expression. Then you could chain them with the bitwise or (||) operator to test the next condition, until the last one where you return the default value.

如果您所有的真值条件都计算为真值(因此,如果强制转换为布尔值,则问号和分号之间的值将计算为真...),您可以使三元表达式false作为假表达式返回。然后你可以用按位或 ( ||) 运算符链接它们来测试下一个条件,直到最后一个返回默认值。

In the example below, the "condsXXX" array represent the result of evaluating the conditions. "conds3rd" simulates the 3rd condition is true and "condsNone" simulates no condition is true. In a real life code, you'd have the conditions "inlined" in the assignment expression:

在下面的示例中,“condsXXX”数组表示评估条件的结果。“conds3rd”模拟第三个条件为真,“condsNone”模拟没有条件为真。在现实生活中的代码中,您将在赋值表达式中“内联”条件:

var conds3rd = [false, false, true];
var condsNone = [false, false, false];

var val3rd = (conds3rd[0] ? 1 : false) ||
  (conds3rd[1] ? 2 : false) ||
  (conds3rd[2] ? 3 : 4);

var valNone = (condsNone[0] ? 1 : false) ||
  (condsNone[1] ? 2 : false) ||
  (condsNone[2] ? 3 : 4);

alert(val3rd);
alert(valNone);

Your example could end up like below:

您的示例最终可能如下所示:

word = ((res.distance === 0) ? 'a' : false) ||
    ((res.distance === 1 && res.difference > 3) ? 'b' : false) ||
    ((res.distance === 2 && res.difference > 5 && String(res.key).length > 5) ? 'c' : 'd';

As a side note, I don't feel it's a good looking code, but it is quite close to using the pure ternary operator like you aspire to do...

作为旁注,我不认为这是一个好看的代码,但它非常接近于像你渴望做的那样使用纯三元运算符......

回答by Doug Coburn

If you are looking to use const with a nested ternary expression, you can replace the ternary with a function expression.

如果您希望将 const 与嵌套的三元表达式一起使用,则可以将三元替换为函数表达式。

const res = { distance: 1, difference: 5 };

const branch = (condition, ifTrue, ifFalse) => condition?ifTrue:ifFalse;
const word = branch(
  res.distance === 0,    // if
  'a',                   // then
  branch(                // else
    res.distance === 1 && res.difference > 3,   // if
    'b',                                        // then
    branch(                                     // else
      res.distance === 2 && res.difference > 5,   // if
      'c',                                        // then
      'd'                                         // else
    )
  )
);

console.log(word);

or using named parameters via destructuring...

或通过解构使用命名参数...

const branch2 = function(branch) {
  return branch.if ? branch.then : branch.else;
}

const fizzbuzz = function(num) {
  return branch2({
    if: num % 3 === 0 && num % 5 === 0,
    then: 'fizzbuzz',
    else: branch2({
        if: num % 3 === 0,
        then: 'fizz',
        else: branch2({
          if: num % 5 === 0,
          then: 'buzz',
          else: num
        })
      })
  });
}

console.log(
  [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16].map(
    cv => fizzbuzz(cv)
  )
);

... edit: It may be clearer to model it after the python if expression like this:

...编辑:如果表达式如下,在python之后建模可能更清楚:

const res = { distance: 1, difference: 5 };

const maybe = def => ({
  if: expr => {
    if (expr) {
      return { else: () => def };
    } else {
      return { else: els => els };
    }
  }
});
const word = maybe('a').if(res.distance === 0).else(
  maybe('b').if(res.distance === 1 && res.difference > 3).else(
    maybe('c').if(res.distance === 2 && res.difference > 5).else('d')
  )
);
console.log(word);

回答by Ambyjkl

I faced this too recently and a google search led me here, and I want to share something I discovered recently regarding this:

我最近也遇到了这个问题,谷歌搜索把我带到了这里,我想分享我最近发现的一些关于这个的东西:

a && b || c

a && b || c

is almost the same thing as

几乎是一样的

a ? b : c

a ? b : c

as long as bis truthy. If bisn't truthy, you can work around it by using

只要b是真实的。如果b不是真的,你可以通过使用来解决它

!a && c || b

!a && c || b

if cis truthy.

如果c是真的。

The first expression is evaluated as (a && b) || cas &&has more priority than ||.

第一个表达式被评价为(a && b) || c作为&&具有比更优先||

If ais truthy then a && bwould evaluate to bif bis truthy, so the expression becomes b || cwhich evaluates to bif it is truthy, just like a ? b : cwould if ais truthy, and if ais not truthy then the expression would evaluate to cas required.

If ais truthy thena && b将评估为bif bis truthy,因此表达式变为ifb || c评估b为 true,就像a ? b : cif ais truthy 一样,如果a不是 true,则表达式将c根据需要评估为。

Alternating between the &&and ||trick and ?and ||in the layers of the statement tricks the no-nested-ternary eslint rule, which is pretty neat (although I would not recommend doing so unless there is no other way out).

在语句的&&||技巧和?||在语句的层之间交替使用无嵌套三元 eslint 规则,它非常简洁(尽管我不建议这样做,除非没有其他出路)。

A quick demonstration:

快速演示:

true ? false ? true : true ? false : true ? true ? true : false : true : true
// which is interpreted as
true ? (false ? true : (true ? false : (true ? (true ? true : false) : true))) : true
// now with the trick in alternate levels
true ? (false && true || (true ? false : (true && (true ? true : false) || true))) : true
// all of these evaluate to false btw

I actually cheated a bit by choosing an example where bis always truthy, but if you are just setting strings then this should work fine as even '0'is ironically truthy.

我实际上通过选择一个b始终为真的示例来作弊,但是如果您只是设置字符串,那么这应该可以正常工作,因为即使'0'是具有讽刺意味的真实。

回答by ap-o

I've been using a switch(true) statement for these cases. In my opinion this syntax feels slightly more elegant than nested if/else operators

对于这些情况,我一直在使用 switch(true) 语句。在我看来,这种语法比嵌套的 if/else 运算符更优雅

switch (true) {
  case condition === true :
    //do it
    break;
  case otherCondition === true && soOn < 100 :
    // do that
    break;
}