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

这是我知道的唯一方法:

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

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

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


当前回答

有几种方法可以找到答案。您可以使用内置的Array方法。最常用的是数组查找方法。

const arr1 = [1, 2, 3, 4, 5]
const result = arr1.find(ele => ele === 4)
console.log(result) //4

const result2 = arr1.find(ele => ele === 6)
console.log(result2) //undefined
/* 
If the element is present inside the array
then it will return the first element that
satisfies the given condition. Otherwise
undefined will return.
*/

其他回答

上面的答案假设是基元类型,但如果您想知道数组是否包含具有某种特征的对象,array.protocol.some()是一个很好的解决方案:

const items = [ {a: '1'}, {a: '2'}, {a: '3'} ]

items.some(item => item.a === '3')  // returns true
items.some(item => item.a === '4')  // returns false

它的好处是,一旦找到元素,迭代就被中止,从而避免了不必要的迭代周期。

此外,它很适合if语句,因为它返回布尔值:

if (items.some(item => item.a === '3')) {
  // do something
}

*正如jamess在评论中指出的那样,在2018年9月回答这个问题时,Array.protocol.some()是完全支持的:caniuse.com支持表

希望更快的双向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

使用idnexOf()是一个很好的解决方案,但您应该隐藏嵌入的实现indexOf(()函数,该函数使用~运算符返回-1:

function include(arr,obj) { 
    return !!(~arr.indexOf(obj)); 
} 

简单的解决方案:ES6功能“包含”方法

let arr = [1, 2, 3, 2, 3, 2, 3, 4];

  arr.includes(2) // true

  arr.includes(93) // false

正如其他人提到的,您可以使用Array.indexOf,但并非所有浏览器都可以使用。这是来自的代码https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Array/indexOf以使其在旧浏览器中工作相同。

indexOf是ECMA-262标准的最新添加;因此,它可能并非在所有浏览器中都存在。您可以通过插入脚本开头的以下代码,允许使用indexOf在本机不支持它的实现中。这算法完全是ECMA-262第5版中规定的算法,假设Object、TypeError、Number、Math.floor、Math.abs和Math.max具有其原始价值。

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 > 1) {
            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;
    }
}