在JavaScript中如何检查数组是否包含某个值?

4890

什么是在JavaScript中查找数组是否包含特定值的最简洁和高效的方法?

以下是我所了解的唯一方法:

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

有没有更好、更简洁的方法来完成这个任务?

这与Stack Overflow问题 Best way to find an item in a JavaScript Array?非常相关,该问题讨论了使用indexOf在数组中查找对象的方法。


64
刚刚测试了一下,你的方法实际上是跨浏览器最快的方式:http://jsperf.com/find-element-in-obj-vs-array/2(除了在变量中预先保存a.length之外)。而使用indexOf(如$.inArray中所示)则慢得多。 - Jörn Berkefeld
23
许多人回复说 Array#indexOf 是在这里最好的选择。但是,如果你想要一些可以正确转换为布尔值的东西,请使用以下代码:~[1,2,3].indexOf(4) 将返回 0,被评估为 false,而 ~[1,2,3].indexOf(3) 将返回 -3,被评估为 true。 - lordvlad
13
使用~不能将值转换为布尔型,你需要使用!。但在本例中,你需要检查是否等于-1,所以函数可能会结束返回[1,2,3].indexOf(3) === -1。~是二进制非运算符,它会独立地翻转每个位的值。 - mcfedr
19
[1,2,3].indexOf(4)实际上会返回-1。正如@mcfedr指出的,~是比特非运算符,参见ES5 11.4.8。问题在于,由于-1的二进制表示只包含1,其补码为0,这会被评估为false。任何其他数字的补码都不为零,因此为true。所以,~可以很好地与indexOf一起使用。 - mknecht
7
标题有误导性。[[1,2],[3,4]].includes([3,4])在哪里? - mplungjan
显示剩余4条评论
62个回答

36

一句话概括:

function contains(arr, x) {
    return arr.filter(function(elem) { return elem == x }).length > 0;
}

14
array.filter(e=>e==x).length > 0 相当于 array.some(e=>e==x),但 some 更高效。 - Apolo

35

27

我使用以下内容:

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

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

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

24
function contains(a, obj) {
    return a.some(function(element){return element == obj;})
}

Array.prototype.some() 在第5版ECMA-262标准中被添加。


如果使用ES6,可以缩短为contains = (a, obj) => a.some((element) => element === obj)) - xkeshav
即使是IE9也支持ECMAScript 5中的Array.prototype.some() - Suncat2000

21

如果您使用的是JavaScript 1.6或更高版本(Firefox 1.5或更高版本),则可以使用Array.indexOf。否则,我认为您最终会得到与原始代码类似的东西。

注:Array.indexOf是一种用于查找数组中特定元素的方法。

20

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

2015

尽管新方法 includes 很好用,但目前基本上没有支持。

我一直在想办法以替换较慢的 indexOf/lastIndexOf 函数。已经找到了一个高效的方法,这个方法是从顶级答案中选出来的 contains 函数,由 @Damir Zekic 提交的,应该是最快的函数。但它也说基准测试是从 2008 年的数据,所以已经过时了。

我也更喜欢使用 while 而不是 for,但我没有具体的理由,所以结束时我用了一个 for 循环写了这个函数。它也可以用 while -- 来实现。

我很好奇迭代时如果同时检查数组的两端是否会更慢。显然不会,因此这个函数比得分最高的函数快约两倍。显然,它也比原生函数快。这是在实际环境中,在这里你永远不知道你正在搜索的值是在数组的开头还是结尾。

当您知道刚刚推送了一个带有值的数组时,使用 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

为了测试,我创建了一个包含10万条记录的数组。

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

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

注意:正如您所看到的,我略微修改了contains函数以反映indexOflastIndexOf的输出(因此基本上是trueindexfalse-1)。 这不应该损害它。

数组原型变量

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


19
有几种方法可以轻松实现(includes,some,find,findIndex)。

const array = [1, 2, 3, 4, 5, 6, 7];

console.log(array.includes(3));
//includes() determines whether an array includes a certain value among its entries

console.log(array.some(x => x === 3)); 
//some() tests if at least one element in the array passes the test implemented by the provided function

console.log(array.find(x => x === 3) ? true : false);
//find() returns the value of the first element in the provided array that satisfies the provided testing function

console.log(array.findIndex(x => x === 3) > -1);
//findIndex() returns the index of the first element in the array that satisfies the provided testing function, else returning -1.

更多关于includes, some, find, findIndex的信息


对于 findIndex,三元运算符不是必需的,对吧?因为 ... > -1 是一个比较操作,本身就是一个布尔值。 - Sreenikethan I
感谢@SreenikethanI提出这个问题 - 我根据你的建议修改了那个例子。 - Ran Turner

17
function inArray(elem,array)
{
    var len = array.length;
    for(var i = 0 ; i < len;i++)
    {
        if(array[i] == elem){return i;}
    }
    return -1;
} 

如果找到了,则返回数组索引,否则返回-1


16
我们使用这个代码片段(适用于对象,数组和字符串):

我们使用这个代码片段(适用于对象,数组和字符串):

/*
 * @function
 * @name Object.prototype.inArray
 * @description Extend Object prototype within inArray function
 *
 * @param {mix}    needle       - Search-able needle
 * @param {bool}   searchInKey  - Search needle in keys?
 *
 */
Object.defineProperty(Object.prototype, 'inArray',{
    value: function(needle, searchInKey){

        var object = this;

        if( Object.prototype.toString.call(needle) === '[object Object]' || 
            Object.prototype.toString.call(needle) === '[object Array]'){
            needle = JSON.stringify(needle);
        }

        return Object.keys(object).some(function(key){

            var value = object[key];

            if( Object.prototype.toString.call(value) === '[object Object]' || 
                Object.prototype.toString.call(value) === '[object Array]'){
                value = JSON.stringify(value);
            }

            if(searchInKey){
                if(value === needle || key === needle){
                return true;
                }
            }else{
                if(value === needle){
                    return true;
                }
            }
        });
    },
    writable: true,
    configurable: true,
    enumerable: false
});

用法:

var a = {one: "first", two: "second", foo: {three: "third"}};
a.inArray("first");          //true
a.inArray("foo");            //false
a.inArray("foo", true);      //true - search by keys
a.inArray({three: "third"}); //true

var b = ["one", "two", "three", "four", {foo: 'val'}];
b.inArray("one");         //true
b.inArray('foo');         //false
b.inArray({foo: 'val'})   //true
b.inArray("{foo: 'val'}") //false

var c = "String";
c.inArray("S");        //true
c.inArray("s");        //false
c.inArray("2", true);  //true
c.inArray("20", true); //false

16

如果您需要多次检查数组中某个对象是否存在,那么也许应该考虑:

  1. 在数组中始终保持排序,可通过在数组中进行插入排序(将新对象放置在正确的位置)来实现;
  2. 将更新对象视为删除+排序插入操作,并且
  3. contains(a, obj)中使用二分查找

3
如果可能的话,最好完全停止使用数组,而是像MattMcKnight和ninjagecko建议的那样,使用一个对象作为字典。 - joeytwiddle

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