替代JS

时间:2015-08-29 18:18:12

标签: javascript ternary-operator eslint

我个人喜欢三元运算符,而且我认为它们使复杂的表达式很容易消化。拿这个:

  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声明,但不知道是否还有其他选择。

14 个答案:

答案 0 :(得分:17)

这里的替代方案基本上是:

  1. 您不想做的if / else
  2. switchif / else
  3. 相结合

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

    我会去#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 - 语法语言系列中不常见的事实:{ {1}}语句可以是表达式,并且与源代码顺序中的switch值匹配:

    case

    那有多难看? : - )

答案 1 :(得分: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' ;

答案 2 :(得分: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';

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

答案 3 :(得分: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;

答案 4 :(得分:2)

你可以写一个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

答案 5 :(得分:2)

有时我们(或者只是喜欢)使用单行表达式或变量定义。 因此,我们可以将破坏性分配与三元运算符结合使用。例如,

是:

const projectDimension =  ndx.dimension(function (d) {
    return d.project_id;
});

const teachers = ndx.dimension(function (d) {
  return d.teachers;
});

const teachersGroup = teachers.group();
const reducer = reductio()
  .exception(function(d) { return d.project_id; })
  .exceptionCount(true)(teachersGroup) 
  
//teachersGroup.top(Infinity);  
console.log(teachersGroup.top(Infinity))

让我们更新为:

quicksort.js:142 Uncaught RangeError: Maximum call stack size exceeded

它甚至仍然保持相对良好的可读性。

答案 6 :(得分: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);

答案 7 :(得分:1)

如果你使用 lodash 你可以使用 _.cond

带 lodash/fp 的免费版本:

 const getWord = _.cond([
  [_.flow(_.get('distance'), _.eq(0)), _.constant('a')],
  [_.flow(_.get('distance'), _.eq(1)) && _.flow(_.get('difference'), _.gt(3)), _.constant('b')],
  [
    _.flow(_.get('distance'), _.eq(2))
    && _.flow(_.get('difference'), _.gt(5))
    && _.flow(_.get('key'), _.toString, _.gt(5)),
    _.constant('c'),
  ],
  [_.stubTrue, _.constant('d')],
]);

答案 8 :(得分:1)

如果你想要一些不太可读的东西......这可能适合你。编写一个通用函数来获取条件数组(按照你编写 if/else 的顺序)和赋值数组。使用 .indexOf() 查找条件中的第一个真值,并返回该索引处的赋值数组值。顺序很关键,条件需要按索引与您想要的分配相匹配:

{{1}}

您可以修改以处理truthy而不是struct true,如果indexOf为-1,请注意未定义的返回

答案 9 :(得分:0)

我最近也遇到过这种情况,谷歌搜索引领我到这里,我想分享一些我最近发现的关于此事的内容:

$('select[name=city]').val(response.city); $('.selectpicker').selectpicker('refresh');

几乎与

相同

a && b || c

只要a ? b : c是真实的。如果b不真实,您可以使用

解决此问题

b

如果!a && c || b是真实的。

第一个表达式的评估结果为c,因为(a && b) || c的优先级高于&&

如果||真实,那么如果a真实,则a && b将评估为b,因此表达式变为b,其评估为b || c如果它是真实的,就像b如果a ? b : c是真实的,如果a不是真的那么表达式将根据需要评估为a

在语句图层中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具有讽刺意味的真相。

答案 10 :(得分:0)

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

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

答案 11 :(得分: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))

答案 12 :(得分:0)

我个人喜欢对一个衬垫使用三元表达式。 尽管如此,我不得不同意嵌套三元表达式会导致代码粗略。

我最近开始使用 Object 构造函数来编写更清晰的代码:

let param: "one" | "two" | "three";

// Before
let before: number = param === "one" ? 1 : param === "two" ? 2 : 3;

// After
let after: number = Object({
    one: 1,
    two: 2,
    three: 3
})[param];

现实生活中的例子:

const opacity =
    Platform.OS === "android"
      ? 1
      : Object({
          disabled: 0.3,
          pressed: 0.7,
          default: 1,
        })[(disabled && "disabled") || (pressed && "pressed") || "default"];

答案 13 :(得分:0)

ES6 打开了大门,这是对 switch 语句的不同看法。

Object.entries({
  ['a']: res.distance === 0,
  ['b']: res.distance === 1 && res.difference > 3,
  ['c']: (res.distance === 2 && res.difference > 5 && String(res.key).length > 5) ? 'c'
}).filter(n => n[1] === true)[0][0]