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

这是我知道的唯一方法:

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

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

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


当前回答

表演

今天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个元素

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

其他回答

字面意思:

(使用Firefox v3.6,如前所述,带有for in注意事项(然而,下面的用法可能支持中的这一目的!即,枚举通过属性索引实际存在的数组元素(尤其是,数组长度属性未在for in属性列表中枚举!)。)

(拖放以下完整URI以进行即时模式浏览器测试。)

JavaScript:

  function ObjInRA(ra){var has=false; for(i in ra){has=true; break;} return has;}

  function check(ra){
      return ['There is ',ObjInRA(ra)?'an':'NO',' object in [',ra,'].'].join('')
  }
  alert([
            check([{}]), check([]), check([,2,3]),
            check(['']), '\t (a null string)', check([,,,])
        ].join('\n'));

其显示:

There is an object in [[object Object]].
There is NO object in [].
There is an object in [,2,3].
There is an object in [].
     (a null string)
There is NO object in [,,].

皱纹:如果要查找“特定”对象,请考虑:

JavaScript:警报({}!={});警报({}!=={});

因此:

JavaScript:

 obj = {prop:"value"}; 
 ra1 = [obj]; 
 ra2 = [{prop:"value"}];
 alert(ra1[0] == obj); 
 alert(ra2[0] == obj);

ra2通常被认为“包含”obj作为文本实体{prop:“value”}。

一个非常粗糙、简单、幼稚的解决方案(如代码需要增强资格):

JavaScript:

  obj={prop:"value"};   ra2=[{prop:"value"}];
  alert(
    ra2 . toSource() . indexOf( obj.toSource().match(/^.(.*).$/)[1] ) != -1 ?
      'found' :
      'missing' );

请参阅ref:在JavaScript数组中搜索对象。

原型是这样做的:

/**
 *  Array#indexOf(item[, offset = 0]) -> Number
 *  - item (?): A value that may or may not be in the array.
 *  - offset (Number): The number of initial items to skip before beginning the
 *      search.
 *
 *  Returns the position of the first occurrence of `item` within the array &mdash; or
 *  `-1` if `item` doesn't exist in the array.
**/
function indexOf(item, i) {
  i || (i = 0);
  var length = this.length;
  if (i < 0) i = length + i;
  for (; i < length; i++)
    if (this[i] === item) return i;
  return -1;
}

另请参见此处了解它们是如何连接的。

如果您只是试图检查某个值是否包含在集合中,则使用Set更合适,因为数组可以具有重复的值,而Set不能。此外,用set.has替换array.includes可以将性能从O(n2)提高到O(n)。当您必须查找同一集合的多个值时,这将非常有用。因此,如果您只是要查找一个值,那么使用set.has没有任何好处,您可以只使用array.includes。

创建了一个jsbench演示,您可以运行它来检查性能。

测试执行截图:

我使用以下方法:

Array.prototype.contains = function (v) {
    return this.indexOf(v) > -1;
}

var a = [ 'foo', 'bar' ];

a.contains('foo'); // true
a.contains('fox'); // false

如果你使用的是JavaScript 1.6或更高版本(Firefox 1.5或更高),你可以使用Array.indexOf。