如何编写三元运算符(aka if)表达式而不重复自己

时间:2017-04-12 03:27:06

标签: javascript conditional-operator

例如,像这样:

foo

有更好的方式来写吗?同样,我不是在寻找上面确切问题的答案,只是你可能在三元运算符表达式中重复操作数的例子......

17 个答案:

答案 0 :(得分:175)

就我个人而言,我发现最好的方法仍然是好的旧if声明:

var value = someArray.indexOf(3);
if (value === -1) {
  value = 0;
}

答案 1 :(得分:97)

代码应该是可读的,所以简洁并不意味着要花费任何成本 - 因为你应该重新发布到https://codegolf.stackexchange.com/ - 所以我建议使用名为index的第二个局部变量来最大化阅读可理解性(运行成本也很低,我注意到):

var index = someArray.indexOf( 3 );
var value = index == -1 ? 0 : index;

但如果你真的想减少这种表达,因为你对你的同事或项目合作者来说是一个残酷的虐待狂,那么你可以使用以下四种方法:

1:var语句中的临时变量

当用逗号分隔时,您可以使用var语句定义(和分配)第二个临时变量index的能力:

var index = someArray.indexOf(3), value = index !== -1 ? index: 0;

2:自动执行匿名函数

另一种选择是自动执行匿名函数:

// Traditional syntax:
var value = function( x ) { return x !== -1 ? x : 0 }( someArray.indexOf(3) );

// ES6 syntax:
var value = ( x => x !== -1 ? x : 0 )( someArray.indexOf(3) );

3:逗号运算符

还有臭名昭着的逗号运营商" JavaScript支持哪些,它也存在于C和C ++中。

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Comma_Operator

  

如果要在需要单个表达式的位置包含多个表达式,可以使用逗号运算符。

您可以使用它来引入副作用,在这种情况下,通过重新分配到value

var value = ( value = someArray.indexOf(3), value !== -1 ? value : 0 );

这是有效的,因为var value首先被解释(因为它是一个声明),然后是最左边的,最里面的value赋值,然后逗号运算符的右侧,然后是三元运算符 - 所有合法的JavaScript。

4:在子表达式中重新分配

评论员@IllusiveBrian指出,如果将value的赋值用作带括号的子表达式,则不需要使用逗号运算符(在前面的示例中):

var value = ( ( value = someArray.indexOf(3) ) !== -1 ? value : 0 );

请注意,在逻辑表达式中使用否定词对于人类来说可能更难以遵循 - 因此,通过将idx !== -1 ? x : y更改为idx == -1 ? y : x,可以简化以上所有示例以进行阅读:

var value = ( ( value = someArray.indexOf(3) ) == -1 ? 0 : value );

答案 2 :(得分:53)

数字

您可以使用Math.max()功能。

var value = Math.max( someArray.indexOf('y'), 0 );

如果是这种情况,它将保留0结果的边界,直到第一个结果大于0。如果indexOf的结果为-1,则会返回0,大于-1

对于布尔值和布尔值y

对于JS,没有一般规则AFAIK,因为如何评估falsy值。

但是如果有什么东西可以帮助你,那么大部分时间都是or运算符(||):

// Instead of
var variable = this_one === true ? this_one : or_this_one;
// you can use
var variable = this_one || or_this_one;

您必须非常小心,因为在您的第一个示例中,indexOf可以返回0,如果您评估0 || -1,它将返回-1,因为{{ 1}}是falsy值。

答案 3 :(得分:26)

不是,只是使用另一个变量。

你的例子概括为类似的东西。

var x = predicate(f()) ? f() : default;

您正在测试计算值,然后在传递某个谓词时将该值分配给变量。避免重新计算计算值的方法很明显:使用变量来存储结果。

var computed = f();
var x = predicate(computed) ? computed : default;

我理解你的意思 - 似乎应该有一些方法来做这个看起来更清洁的方法。但我认为这是实现这一目标的最佳方式(惯用)。如果由于某种原因你在代码中重复了这个模式,你可能会写一个小帮助函数:

var setif = (value, predicate, default) => predicate(value) ? value : default;
var x = setif(someArray.indexOf(3), x => x !== -1, 0)

答案 4 :(得分:17)

编辑:现在是Nullary-coalescing现在在JavaScript中的提议!

使用||

const result = a ? a : 'fallback value';

相当于

const result = a || 'fallback value';

如果将a投放到Boolean返回false,则会为result分配'fallback value',否则为a

请注意边缘情况a === 0,其转换为falseresult将(错误地)转为'fallback value'。使用这样的技巧需要您自担风险。

PS。 Swift等语言具有nil-coalescing运算符(??),其用途类似。例如,在Swift中你会写result = a ?? "fallback value",它非常接近JavaScript的const result = a || 'fallback value';

答案 5 :(得分:8)

使用extract variable refactoring

var index = someArray.indexOf(3);
var value = index !== -1 ? index : 0

使用const代替var会更好。您还可以进行额外的提取:

const index = someArray.indexOf(3);
const condition = index !== -1;
const value = condition ? index : 0;

在实践中,使用比indexconditionvalue更有意义的名称。

const threesIndex = someArray.indexOf(3);
const threeFound = threesIndex !== -1;
const threesIndexOrZero = threeFound ? threesIndex : 0;

答案 6 :(得分:6)

我个人更喜欢两种变体:

  1. 如果像@slebetman建议那样纯粹

  2. 单独的函数,用默认值替换无效值,如下例所示:

  3. function maskNegative(v, def) {
      return v >= 0 ? v : def;
    }
    
    Array.prototype.indexOfOrDefault = function(v, def) {
      return maskNegative(this.indexOf(v), def);
    }
    
    var someArray = [1, 2];
    console.log(someArray.indexOfOrDefault(2, 0)); // index is 1
    console.log(someArray.indexOfOrDefault(3, 0)); // default 0 returned
    console.log(someArray.indexOfOrDefault(3, 123)); // default 123 returned

答案 7 :(得分:6)

您可能正在寻找一个合并运营商。幸运的是,我们可以利用Array原型创建一个:

Array.prototype.coalesce = function() {
    for (var i = 0; i < this.length; i++) {
        if (this[i] != false && this[i] != null) return this[i];
    }
}

[null, false, 0, 5, 'test'].coalesce(); // returns 5

通过向函数添加参数,可以进一步推广这种情况:

Array.prototype.coalesce = function(valid) {
    if (typeof valid !== 'function') {
        valid = function(a) {
            return a != false && a != null;
        }
    }

    for (var i = 0; i < this.length; i++) {
        if (valid(this[i])) return this[i];
    }
}

[null, false, 0, 5, 'test'].coalesce(); // still returns 5
[null, false, 0, 5, 'test'].coalesce(function(a){return a !== -1}); // returns null
[null, false, 0, 5, 'test'].coalesce(function(a){return a != null}); //returns false

答案 8 :(得分:5)

我喜欢@ slebetman的回答。其中的评论表达了对变量处于“中间状态”的担忧。如果这是你的一个大问题,那么我建议将其封装在一个函数中:

function get_value(arr) {
   var value = arr.indexOf(3);
   if (value === -1) {
     value = 0;
   }
   return value;
}

然后致电

var value = get_value( someArray );

如果你在其他地方使用它们,你可以做更多的通用功能,但如果它是一个非常具体的情况,不要过度工程。

但说实话,我会像@slebetman一样做,除非我需要从几个地方重新使用。

答案 9 :(得分:4)

我可以通过两种方式查看您的问题:您要么想减少行长度,要么特别想避免在三元组中重复变量。第一个是微不足道的(许多其他用户已发布示例):

var value = someArray.indexOf(3) !== -1 ? someArray.indexOf(3) : 0;

可以(并且应该在给定函数调用的情况下)缩短为:

var value = someArray.indexOf(3);
value = value !== -1 ? value : 0;

如果您正在寻找一种更通用的解决方案,以防止在三元组中重复变量,例如:

var value = conditionalTest(foo) ? foo : bar;

其中foo只出现一次。丢弃表格的解决方案:

var cad = foo;
var value = conditionalTest(foo) ? cad : bar;

虽然技术上正确但却忽略了重点,那么你运气不好。有些操作符,函数和方法都拥有您所寻求的简洁语法,但根据定义,这些结构不是三元运算符

示例:

javascript,当LHS为||时使用falsey返回RHS:

var value = foo || bar; // equivalent to !foo ? bar : foo

答案 10 :(得分:3)

使用帮助函数:

function translateValue(value, match, translated) {
   return value === match ? translated : value;
}

现在你的代码非常易读,而且没有重复。

var value = translateValue(someArray.indexOf(3), -1, 0);

编码问题的层次结构是:

  1. 正确(包括真实性能或SLA问题)
  2. 清除
  3. 简明
  4. 快速
  5. 到目前为止,页面上的所有答案似乎都是正确的,但我认为我的版本具有最高的清晰度,这比简洁更重要。如果你不计算辅助函数 - 因为它可以重用 - 它也是最简洁的。不幸的是,使用辅助函数的一些类似建议使用了一个lambda,对我而言,它只是掩盖了它正在做的事情。一个更简单的函数有一个目的,不需要lambda,只是值,对我来说更好。

    P.S。如果您喜欢ES6语法:

    const translateValue = (value, match, translated) => value === match ? translated : value;
    let value = translateValue(someArray.indexOf(3), -1, 0); // or const
    

答案 11 :(得分:2)

我认为||运算符可以定制为indexOf

var value = ((someArray.indexOf(3) + 1) || 1) - 1;

返回的值向上移动1,从-1开始为0,这是假的,因此被第二个1替换。然后它被移回。

但是,请记住,可读性优于避免重复。

答案 12 :(得分:2)

这是一个简单的解决方案bitwise NOT,默认值为-1,后来会产生零。

index = ~(~array.indexOf(3) || -1);

它基本上使用双按位NOT,它返回原始值或默认值,在应用按位NOT后返回零。

让我们看看真相表:

 indexOf    ~indexOf   boolean    default     value      result         comment
---------  ---------  ---------  ---------  ---------  ---------  ------------------
      -1          0     falsy          -1         -1          0   take default value
       0         -1    truthy                     -1          0
       1         -2    truthy                     -2          1
       2         -3    truthy                     -3          2

答案 13 :(得分:0)

鉴于问题中的示例代码,不清楚如何确定3是否设置在0的索引someArray。从-1返回的.indexOf()在这种情况下很有价值,目的是排除可能匹配的推定不匹配。

如果数组中未包含3,则会返回-1。我们可以将1添加到.indexOf()的结果,以评估结果为false-1,其后是|| OR运算符和{{ 1}}。引用0时,减去value以获取数组元素的索引或1

这导致简单地使用-1并在.indexOf()条件下检查-1。或者,将if定义为value,以避免可能混淆与原始参考相关的评估条件的实际结果。

&#13;
&#13;
undefined
&#13;
&#13;
&#13;

答案 14 :(得分:0)

您可以使用重新分配:

  • 将变量初始化为一个值
  • 使用&&运算符的序列化进行重新分配,因为如果第一个条件为false,则不会计算第二个表达式

实施例

var value = someArray.indexOf(3);
value == -1 && (value=0);

var someArray = [4,3,2,1];

var value = someArray.indexOf(1);
value == -1 && (value=0);
console.log('Found:',value);

var value = someArray.indexOf(5);
value == -1 && (value=0);
console.log('Not Found:',value);

答案 15 :(得分:0)

三元就像是if-else,如果你不需要其他部分,为什么不只是一个而不是..

if ((value = someArray.indexOf(3)) < 0) value = 0;

答案 16 :(得分:0)

对于这种特殊情况,您可以使用逻辑||运算符进行短路。由于0被认为是虚假的,因此您可以+1进入索引,因此,如果index+10,那么您将获得回报的右侧结果,否则,您将得到index+1。然后,您可以根据此结果-1来获取索引:

const someArray = [1, 2, 3, 4];
const v = ((someArray.indexOf(3)+1) || 1)-1;
console.log(v);