什么是将一个值与多个值进行比较的最佳方式?

99

如何以最简单的方式将一个值与多个选项进行比较?

我知道有很多方法可以做到这一点,但我正在寻找最整洁的方法。

我之所以问这个问题,是因为我曾经希望以下代码可行(显然它不可行):

if (foobar == (foo||bar) ) {
     //do something
}

2
你可以使用javascript的test函数,如 if(/foo|bar|ow|my|javascript|works/.test( foobar )) { /*do something*/ }。这个问题和我的类似 - Ron van der Heijden
我在这里要注意,foo 不会正确评估,它不会检查 bar,例如 1 === (2 || 1) 将返回 false... - Neil
3
一个有点老的线程,但在ES6中:如果([foo,bar].includes(foobar) { //做一些事情 }将会执行。 - Loïc V
8个回答

168

不要过于聪明,特别是当它不必要地影响性能时。如果你真的有大量的比较需要进行,只需好好格式化即可。

if (foobar === foo ||
    foobar === bar ||
    foobar === baz ||
    foobar === pew) {
     //do something
}

39
如果您按照降序排列真实概率的术语,可以加快速度。 :) - wenzul
在我的世界里,可读性等同于美观程度。这是最易读的。 - LCIII
这个方法适用于在编写代码时已知要进行比较的项目,但可能不适用于那些需要与变量进行比较的情况。 - wtanaka.com
你可以使用 Array.prototype.every():[foo, bar].every(elem => elem === comparedValue); - Денищук Павло Миколайович
1
改用 includesif (['foo', 'bar', 'baz', 'pew'].includes(foobar)) { //做一些事情 } - Gss Venkatesh

88
我平常做的是将这些多个值放入一个数组中,例如:
var options = [foo, bar];

然后,使用 indexOf()。

if(options.indexOf(foobar) > -1){
   //do something
}

为了美观:

if([foo, bar].indexOf(foobar) +1){
   //you can't get any more pretty than this :)
}

对于旧浏览器:

( https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Array/indexOf )
if (!Array.prototype.indexOf) {
    Array.prototype.indexOf = function (searchElement /*, fromIndex */ ) {
        "use strict";
        if (this == null) {
            throw new TypeError();
        }
        var t = Object(this);
        var len = t.length >>> 0;
        if (len === 0) {
            return -1;
        }
        var n = 0;
        if (arguments.length > 0) {
            n = Number(arguments[1]);
            if (n != n) { // shortcut for verifying if it's NaN
                n = 0;
            } else if (n != 0 && n != Infinity && n != -Infinity) {
                n = (n > 0 || -1) * Math.floor(Math.abs(n));
            }
        }
        if (n >= len) {
            return -1;
        }
        var k = n >= 0 ? n : Math.max(len - Math.abs(n), 0);
        for (; k < len; k++) {
            if (k in t && t[k] === searchElement) {
                return k;
            }
        }
        return -1;
    }
}

2
数组的 indexOf 方法只在 IE 9 及以上版本中提供,因此我建议在 IE 8 退出市场之前不要使用它(可惜这还需要很长时间)。话虽如此,MDN 提供了适用于不支持该方法的浏览器的示例实现代码。 - Reid
1
Array.indexOf 方法仅支持 Javascript 1.6 及更高版本,因此您需要为旧版浏览器提供备用方案。 - Guffa
9
ES6 中新的方法是使用 includes:https://dev59.com/JHE95IYBdhLWcg3wKqsk#2555311 - baptx
1
@baptx 那应该是第一选择。更易读,就像 Python 中的 foo in (bar, baz) 一样。 - machinekoder
1
@l33t 哈哈,好笑。显然不是,但也不至于那么夸张... 我会使用 [a, b, c, ...].includes(val)。 - André Alçada Padez
显示剩余2条评论

42

由于还没有人添加明显的解决方案,这个方案适用于两个比较,我将提供它:

if (foobar === foo || foobar === bar) {
     //do something
}

如果你有大量的值(也许是数百或数千个),那么我建议使用Set,因为它可以使比较代码变得简单干净,并且在运行时速度很快:

// pre-construct the Set
var tSet = new Set(["foo", "bar", "test1", "test2", "test3", ...]);

// test the Set at runtime
if (tSet.has(foobar)) {
    // do something
}

在ES6之前,你可以使用许多Set polyfill中的一个。其中一个被描述在这个其他答案中。


1
Set比本地优化的字符串比较仍然慢。让浏览器进行优化。试图聪明地超越浏览器的人几乎总是最终得到更慢的代码。 - Jack G
3
@JackGiffin - 你在这里提出了什么建议?我回答的第一部分只是最简单的比较,JS引擎可以按照其喜欢的方式进行优化。我回答的第二部分使用了一个“Set”,针对的情况是您有很多值要进行比较(数百或数千)。我不明白您提出了什么替代建议或者您认为这些建议有什么问题? - jfriend00
1
Set比普通数组好在哪里:if(['foo', 'bar'].includes(value)) - DIES
7
@DIES - Set 使用哈希表查找,而.includes()使用线性搜索。当集合中的项目超过几个时,使用Set将比使用.includes()更快地查找项目。此外,对于Set.add()可以防止重复项。 - jfriend00
当处理大量数据时,Set.has比Array.includes明显更快。在处理小型数据集时,您可以使用Array.includes。 - Dale Ryan

25
您可以使用 switch 语句:
switch (foobar) {
  case foo:
  case bar:
    // do something
}

18

仅仅为了好玩,因为这个问答似乎是关于语法微观分析的,对André Alçada Padez的建议进行了微小的修改:

(当然也要考虑他包含的IE9之前的shim/shiv/polyfill)

if (~[foo, bar].indexOf(foobar)) {
    // pretty
}

3
!!~['foo', 'bar'].indexOf('foo') - Pavel Levin
@PavelLevin,你不需要使用!!,因为if已经测试了表达式的真实性。 - Unmitigated

13

为什么不像下面这样从数组中使用 indexOf

if ([foo, bar].indexOf(foobar) !== -1) {
    // do something
}

这是纯JavaScript,没有任何框架或库,但在IE 9以下的浏览器上无法使用


已经提到了两次几乎相同的代码片段。 - Jack G
非常有趣的使用方式。我没有想象过这种语法。感谢以这种聪明的方式分享。 - MrBB

1

(foobar == foo || foobar == bar) 如果你只是比较基于单个整数、枚举值或字符串对象的表达式,可以使用 switch 语句。详见switch 语句。也可以采用 André Alçada Padez 建议的方法。最终选择将取决于你所做的具体细节。


以上已经提到了三次。在 Stack Overflow 上,你应该只发布那些不在已有答案中的解决方案。 - Jack G
@JackGiffin - 如果您查看时间戳,就会发现在此之前并没有其他多个答案显示出这个解决方案。这里的答案不一定按发布顺序显示。只有我的回答显示了这个解决方案,并且仅比它早3秒,因此作者不可能看到它。即使是被接受的答案也是在这个答案之后才出现的。再次强调,我不知道为什么您要对一个6年前的答案进行攻击。 - jfriend00
@jfriend00 你说得对!我研究了所有的时间戳,发现David才是骗子,而不是JamieSee。JamieSee比David早14分钟回答了问题,而且David的答案和JamieSee完全一样,但是David却得到了积分,而JamieSee没有。让我们给JamieSee更合理的答案点赞。 - Jack G
@JackGiffin - 这不仅仅是关于谁先到达的问题。除了是否在某个地方具有正确的内容之外,一个好答案还有其他方面,比如写得多清晰,解释得多好等等... OP甚至评论了David的答案,称它是“最易读的”。甚至有时候适当地写另一个答案并不是很独特,只是因为现有的答案都没有很好地呈现和解释事情。我并不是在这种情况下暗示任何事情,只是说第一并不是唯一的标准。 - jfriend00
@JackGiffin - 打勾勾应该是给最佳答案的。这是一个比赛,看谁能写出最好的答案。允许提交多个答案。直接复制而没有添加有价值的东西是不被赞同的,但尝试写出更好的解释或解释一些新方面的答案不仅被允许,而且是期望的。再次强调,我并不是在暗示任何特定情况,只是一般性地发表评论。 - jfriend00

0

我喜欢使用数组测试indexOf的漂亮形式,但请注意,这在所有浏览器中都不起作用(因为旧版IExplorers中不存在Array.prototype.indexOf)。

然而,可以通过使用jQuery的$.inArray()函数来实现类似的功能:

if ($.inArray(field, ['value1', 'value2', 'value3']) > -1) {
    alert('value ' + field + ' is into the list'); 
}

这段代码可以更好,所以你不应该测试indexOf是否存在。

在比较时要小心(不要使用== true/false),因为$.inArray返回匹配位置的索引,其中值已被找到,如果索引为0,则当它实际存在于数组中时,它将为false。


请不要使用jQuery(除非您确实希望代码和页面加载速度变慢,如果是这样,请随意使用——我无法阻止疯狂的行为)。 - Jack G

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接