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

问题描述 投票:20回答:8

我个人喜欢三元运算符,并且在我看来,他们使复杂的表达式很容易消化。拿这个:

  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';

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

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

javascript ternary-operator eslint
8个回答
17
投票

您的替代方案基本上是:

  1. 你不想做的if / else
  2. 一个switchif / else结合

我试图提出一个合理的查找映射选项,但它很快就变得不合理了。

我会去#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 (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之后的同一行,但其他人则有不同的风格观点。)

在我看来,#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;
}

最后,我并不是在提倡这一点,你可以利用JavaScript的switchB语法语言系列中不常见的事实: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;
}

这有多难啊? :-)


9
投票

根据我的口味,精心构造的嵌套三元组击败所有那些凌乱的ifs和开关:

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' ;

3
投票

你可以写一个immediately invoked function expression来使它更具可读性:

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


2
投票

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

在下面的示例中,“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);

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

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';

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


2
投票
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';

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

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;

1
投票

如果您希望将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);

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

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)
  )
);

...编辑:在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);

0
投票

我最近也面对这个问题,谷歌搜索引领我到这里,我想分享一些我最近发现的关于此事的内容:

a && b || c

几乎是一样的

a ? b : c

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

!a && c || b

如果c是真的。

第一个表达式被评估为(a && b) || c,因为&&||更优先。

如果a是truthy然后a && b将评估为b如果b是truthy,所以表达式变成b || c,如果它是真实的,则评估为b,就像a ? b : c如果a是truthy,如果a不是truthy然后表达式将评估为c按要求。

&&||技巧以及?||在语句层次之间交替使用了非嵌套三元组合规则,这非常简洁(尽管除非没有别的办法,否则我不建议这样做)。

快速演示:

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

我实际上通过选择b总是真实的例子作弊,但如果你只是设置字符串,那么这应该工作正常,因为即使'0'具有讽刺意味的真理。


0
投票

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

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

0
投票

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

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))
© www.soinside.com 2019 - 2024. All rights reserved.