找出JavaScript数组是否包含值的最简洁有效的方法是什么?

这是我知道的唯一方法:

function contains(a, obj) {
    for (var i = 0; i < a.length; i++) {
        if (a[i] === obj) {
            return true;
        }
    }
    return false;
}

有没有更好、更简洁的方法来实现这一点?

这与堆栈溢出问题密切相关。在JavaScript数组中查找项目的最佳方法是什么?它解决了使用indexOf查找数组中的对象的问题。


当前回答

只是另一种选择

// usage: if ( ['a','b','c','d'].contains('b') ) { ... }
Array.prototype.contains = function(value){
    for (var key in this)
        if (this[key] === value) return true;
    return false;
}

要小心,因为用自定义方法重载javascript数组对象会破坏其他java脚本的行为,从而导致意外行为。

其他回答

2019年更新:这个答案来自2008年(11岁!),与现代JS用法无关。承诺的性能改进基于当时浏览器中的基准测试。它可能与现代JS执行上下文无关。如果您需要一个简单的解决方案,请寻找其他答案。如果您需要最佳的性能,请在相关的执行环境中进行基准测试。

正如其他人所说,通过数组迭代可能是最好的方法,但事实证明,递减while循环是JavaScript中迭代最快的方法。因此,您可能需要按如下方式重写代码:

function contains(a, obj) {
    var i = a.length;
    while (i--) {
       if (a[i] === obj) {
           return true;
       }
    }
    return false;
}

当然,您还可以扩展Array原型:

Array.prototype.contains = function(obj) {
    var i = this.length;
    while (i--) {
        if (this[i] === obj) {
            return true;
        }
    }
    return false;
}

现在,您可以简单地使用以下命令:

alert([1, 2, 3].contains(2)); // => true
alert([1, 2, 3].contains('2')); // => false

希望更快的双向indexOf/lastIndexOf替代方案

2015

虽然新方法包含的内容非常好,但目前支持基本为零。

很长时间以来,我一直在想一种方法来替换缓慢的indexOf/lastIndexOf函数。

已经找到了一种表演方式,看看最热门的答案。我选择了@Damir Zekic发布的contains函数,这应该是最快的函数。但它也指出,基准是2008年的,因此已经过时。

我也更喜欢while而不是for,但不是出于特定原因,我用for循环结束了函数的编写。这也可以在一段时间内完成。

我很好奇,如果我在执行时检查数组的两侧,迭代是否会慢得多。显然没有,所以这个函数比排名靠前的函数快两倍左右。显然,它也比本地的更快。这是在一个真实的环境中,您永远不知道所搜索的值是在数组的开头还是结尾。

当你知道你只是用一个值推送一个数组时,使用lastIndexOf可能是最好的解决方案,但如果你必须遍历大数组,结果可能无处不在,这可能是一个让事情更快的可靠解决方案。

双向indexOf/lastIndexOf

function bidirectionalIndexOf(a, b, c, d, e){
  for(c=a.length,d=c*1; c--; ){
    if(a[c]==b) return c; //or this[c]===b
    if(a[e=d-1-c]==b) return e; //or a[e=d-1-c]===b
  }
  return -1
}

//Usage
bidirectionalIndexOf(array,'value');

性能测试

https://jsbench.me/7el1b8dj80

作为测试,我创建了一个包含100k个条目的数组。

三个查询:在数组的开头、中间和结尾。

我希望你也觉得这很有趣,并测试一下性能。

注意:正如您所看到的,我稍微修改了contains函数,以反映indexOf和lastIndexOf输出(因此,索引基本为true,-1为false)。这不应该伤害它。

阵列原型变体

Object.defineProperty(Array.prototype,'bidirectionalIndexOf',{value:function(b,c,d,e){
  for(c=this.length,d=c*1; c--; ){
    if(this[c]==b) return c; //or this[c]===b
    if(this[e=d-1-c] == b) return e; //or this[e=d-1-c]===b
  }
  return -1
},writable:false, enumerable:false});

// Usage
array.bidirectionalIndexOf('value');

该函数也可以很容易地修改为返回true或false,甚至返回对象、字符串或任何其他值。

下面是while变体:

function bidirectionalIndexOf(a, b, c, d){
  c=a.length; d=c-1;
  while(c--){
    if(b===a[c]) return c;
    if(b===a[d-c]) return d-c;
  }
  return c
}

// Usage
bidirectionalIndexOf(array,'value');

这怎么可能?

我认为,获取数组中反射索引的简单计算非常简单,比实际循环迭代快两倍。

这里有一个复杂的例子,每次迭代进行三次检查,但这仅在计算时间较长时才有可能,因为计算时间较长会导致代码速度减慢。

https://web.archive.org/web/20151019160219/http://jsperf.com/bidirectionalindexof/2

我建议使用下划线库,因为它返回值,并且支持所有浏览器。

下芯js

 var findValue = _.find(array, function(item) {
    return item.id == obj.id;
 });

可以使用具有方法“has()”的Set:

函数包含(arr,obj){var proxy=新集合(arr);if(proxy.has(obj))返回true;其他的return false;}var arr=['快乐','新','年'];console.log(包含(arr,'Happy'));

表演

今天2020.01.07我在Chrome v78.0.0、Safari v13.0.4和Firefox v71.0.0上对MacOs HighSierra 10.13.6进行了测试,测试了15个选定的解决方案。结论

基于JSON、Set和意外find(K、N、O)的解决方案在所有浏览器上都是最慢的es6包括(F)仅在铬上快速基于for(C,D)和indexOf(G,H)的解决方案在大小阵列上的所有浏览器上都非常快,因此它们可能是高效解决方案的最佳选择循环期间索引减少的解决方案(B)可能较慢,因为CPU缓存的工作方式。当搜索到的元素位于阵列长度的66%时,我也对大阵列进行了测试,基于for(C,D,E)的解决方案给出了类似的结果(约630操作/秒-但safari和firefox上的E比C和D慢10-20%)

后果

细节

我执行了两个测试用例:一个是10个元素的数组,一个是100万元素的数组。在这两种情况下,我们都将搜索到的元素放在数组中间。

let log=(name,f)=>console.log(`${name}:3-${f(arr,'s10')}'s7'-${f,'s7')}6-${f设arr=[1,2,3,4,5,'6','7','8','9','10'];//arr=新数组(1000000).fill(123);arr[500000]=7;函数A(A,val){变量i=-1;var n=a.length;而(i++<n){如果(a[i]===val){返回true;}}return false;}函数B(a,val){var i=a.length;而(i-){如果(a[i]===val){返回true;}}return false;}函数C(a,val){对于(var i=0;i<a.length;i++){如果(a[i]===val)返回true;}return false;}函数D(a,val){var len=a.length;对于(var i=0;i<len;i++){如果(a[i]===val)返回true;}return false;} 函数E(a,val){var n=a.length-1;变量t=n/2;对于(变量i=0;i<=t;i++){如果(a[i]==val ||a[n-i]==val)返回true;}return false;}函数F(a,val){return a.includes(val);}函数G(a,val){return a.indexOf(val)>=0;}函数H(a,val){返回~a.indexOf(val);}函数I(a,val){return a.findIndex(x=>x==val)>=0;}函数J(a,val){返回a.some(x=>x===val);}函数K(a,val){const s=JSON.stringify(val);返回a.some(x=>JSON.stringify(x)==s);}函数L(a,val){回来a.every(x=>x!==val);}函数M(a,val){回来a.查找(x=>x==val);}函数N(a,val){返回a.filter(x=>x===val)。长度>0;}函数O(a,val){返回新集合(a).has(val);}日志('A',A);日志('B',B);日志('C',C);日志('D',D);对数('E',E);日志('F',F);日志('G',G);对数('H',H);日志('I',I);日志('J',J);log('K',K);对数('L',L);日志(M’,M);对数('N',N);日志('O',O);此shippet只显示性能测试中使用的函数,而不执行测试本身!

阵列小-10个元素

您可以在此处的机器中执行测试

数组大-1.000.000个元素

您可以在此处的机器中执行测试