如何在不重复的情况下编写三元运算符(又名 if)表达式

IT技术 javascript conditional-operator
2021-02-28 00:24:15

例如,这样的事情:

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

有没有更好的写法?同样,我不是在寻求上述确切问题的答案,只是一个示例,说明何时可能在三元运算符表达式中重复操作数...

6个回答

就我个人而言,我认为最好的方法仍然是古老的if声明:

var value = someArray.indexOf(3);
if (value === -1) {
  value = 0;
}
@Triptych:再看一遍。它根本不使用中间变量。相反,它将结果直接分配给最终变量,然后在满足条件时覆盖它。
2021-04-28 00:24:15
不正确。存储在value第一行之后的是中间值。它不包含正确的值,然后将其固定在下一行,因此是一个中间值。只有在if语句结束后才value包含正确的值。OP 中的三元是一个更好的解决方案,因为它永远不会进入中间状态。
2021-04-30 00:24:15
@JackAidley:“OP 中的三元是更好的解决方案,因为它永远不会进入中间状态。” - 我将不得不不同意。这比 OP 的代码可读性强得多,而且完全符合习惯。它还使 OP 逻辑中的错误对我来说更加明显(即,如果 indexOf() 返回零会发生什么?您如何区分“真实”零和“未找到”零?)。
2021-05-01 00:24:15
需要明确的是,这个答案提倡使用变量来存储中间结果,而不是使用if语句代替三元。三元语句在作为表达式的一部分执行选择时仍然经常有用。
2021-05-03 00:24:15
这与我会做的很接近,除了value这里在技术上发生了变异,我试图避免这种情况。
2021-05-17 00:24:15

代码应该是可读的,所以简洁不意味着不惜一切代价要简洁——为此你应该重新发布到https://codegolf.stackexchange.com/——所以我建议使用名为的第二个局部变量index来最大化阅读理解(我注意到,运行时间成本也最低):

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

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

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 指出,如果将 to 赋值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 );
在第二个示例自执行匿名函数中,您可以省略箭头函数的括号。var value = ( x => x !== -1 ? x : 0 ) ( arr.indexOf(3) );因为只有一个参数。
2021-04-25 00:24:15
所有这些都是那种“聪明”的编码,会让我盯着它看几秒钟,然后想“嗯,我想这行得通”。它们无助于清晰,而且由于代码的阅读量比编写的多,因此更重要。
2021-04-30 00:24:15
@g.rocket 方法 1 是 100% 可读和清晰的,如果您想避免重复,这是唯一可行的方法(如果您调用的是一些复杂且有问题的函数而不是简单的函数,那可能会非常有害indefOf
2021-05-02 00:24:15
同意,#1 的可读性和可维护性很高,其他两个则不然。
2021-05-10 00:24:15
对于#3,我相信您可以简化为var value = ((value = someArray.indexOf(3)) === -1 ? 0 : value);而不是使用逗号。
2021-05-13 00:24:15

对于数字

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

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

它将保持结果的边界0直到第一个结果大于0如果是这种情况。如果结果来自indexOfis-1它将返回 0 大于-1

对于 booleans 和 boolean-y 值

对于 JS 没有一般规则 AFAIK 特别是因为如何评估虚假值。

但是,如果大多数时候可以帮助您的是 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因为0是一个值。

在第一个例子中,我们如何确定3"y"不在索引0someArray
2021-04-27 00:24:15
Math.max例子吗?indexOf返回元素的索引,如果未找到该元素,则返回 -1,因此您有机会获得从 -1 到字符串长度的数字,然后Math.max只需设置从 0 到长度的边界即可消除机会返回-1,
2021-05-10 00:24:15
@guest271314 好主意,但我认为这取决于上下文是否有问题。也许 0 来自哪里并不重要,唯一重要的是它不是 -1。一个例子:也许你需要从数组中挑选一个项目。你想要一个特定的项目(在 OP 中,数字 3),但如果它不在数组中,你仍然需要一个项目,你可以默认为第一个项目,假设你知道数组不是' t 空。
2021-05-13 00:24:15
@mitogh OP 代码的逻辑创建了一个问题,尽管它是通用示例;其中 0 既可以表示0数组中匹配元素的索引,也可以0设置为Math.max()或在 OP 的条件运算符处。考虑var value = Math.max( ["y"].indexOf("y"), 0 )你如何确定哪些0被退回?0传递给Math.max()调用,还是0反映"y"数组内的索引
2021-05-15 00:24:15
谢谢。我想我的例子很糟糕,我只是举了一个一般性的例子哈哈,而不是寻求确切问题的解决方案。我遇到过一些像我想使用三元的例子一样的场景,但最终重复:(
2021-05-20 00:24:15

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

你的例子概括为这样的事情。

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)

编辑:这里是,现在在 JavaScript 中Nullary-coalescing的提议


利用 ||

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

相当于

const result = a || 'fallback value';

如果强制转换aBoolean返回falseresult将被赋值'fallback value',否则为 的值a


请注意边缘情况a === 0,它转换为false并且result将(错误地)采用'fallback value'. 使用此类技巧的风险自负。


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

正确,但他不是在要求具体的例子 > “同样,不是在寻求上述确切问题的答案,只是一个例子,说明你可能在三元组中重复了一些事情” <,请注意,他是在要求一种通用的方法替换重复的三元 (result = a ? a : b)。并且重复三元等价于 || (结果 = a || b)
2021-04-23 00:24:15
那是真的如何||在JavaScript的工作?如果我理解正确,那么它与许多其他主要语言的工作方式不同(我主要考虑 C 及其后代 [C++、Java 等])即使这确实是||JavaScript 的工作方式,我也建议不要使用像这样的技巧需要维护人员了解有关该语言的特殊怪癖。虽然这个技巧很酷,但我认为这是不好的做法。
2021-05-02 00:24:15
PHP (>7.0) 和 C# 也支持空合并运算符。语法糖,但肯定很可爱。
2021-05-10 00:24:15
另请注意,问题是将值与 进行比较-1再说一次,我不能代表 JavaScript 及其怪癖,但通常-1是一个真值,而不是一个假值,因此您的答案在问题的情况下不起作用,当然也不是一般情况,而是仅在特定情况下起作用(但足够常见)子案例。
2021-05-11 00:24:15
这仅在函数失败时返回 falsey 值时有效,但indexOf()不能在此模式中使用。
2021-05-15 00:24:15