题 如何检查数组是否包含JavaScript中的对象?


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

这是我知道的唯一方法:

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

有没有更好,更简洁的方法来实现这一目标?

这与Stack Overflow问题密切相关 在JavaScript数组中查找项目的最佳方法? 其中使用的地址寻找数组中的对象 indexOf


3226
2017-10-25 22:14


起源


刚测试过:对于不同的浏览器,您的方式实际上是最快的: jsperf.com/find-element-in-obj-vs-array/2 (除了在变量中预先保存a.length)同时使用indexOf(如在$ .inArray中)要慢得多 - Jörn Berkefeld
很多人都回答说Array#indexOf是你最好的选择。但是如果你想要一些可以正确转换为布尔值的东西,请使用: ~[1,2,3].indexOf(4) 将返回0,将评估为false,而 ~[1,2,3].indexOf(3) 将返回-3,将评估为真。 - lordvlad
~ 不是你想要用来转换为布尔值的东西,因为你需要它 !。但在这种情况下,您希望检查与-1的相等性,函数可能会结束return [1,2,3].indexOf(3) === -1;  ~ 是二进制不是,它将单独反转值的每个位。 - mcfedr
@Iordvlad [1,2,3].indexOf(4) 实际上 返回-1。正如@mcfedr指出的那样, ~ 是个 按位NOT运算符,见ES5 11.4.8。事情是,因为二进制表示 -1 仅由1个组成,它的补充是 0,评估为假。任何其他数字的补码将为非零,因此也是如此。所以, ~ 工作得很好,经常与之配合使用 indexOf。 - mknecht
标题具有误导性。哪儿是 [[1,2],[3,4]].includes([3,4]) ? - mplungjan


答案:


目前的浏览器有 Array#includes,确实如此 究竟 那, 获得广泛支持,并有一个 填充工具 对于旧浏览器。

> ['joe', 'jane', 'mary'].includes('jane');
true 

你也可以使用 Array#indexOf,这不是直接的,但不要求Polyfills用于过时的浏览器。

jQuery提供 $.inArray,这在功能上等同于 Array#indexOf

underscore.js,一个JavaScript实用程序库,提供 _.contains(list, value)别名 _.include(list, value),两者都使用 指数 内部如果传递JavaScript数组。

其他一些框架提供了类似的方法:

请注意,某些框架将此实现为函数,而其他框架则将该函数添加到数组原型中。


3650
2017-10-25 23:10



MooTools还有Array.contains,它返回一个布尔值,这听起来像是真正的问题。 - Ryan Florence
原型也有 Array.include返回一个布尔值 - user102008
如果您使用的是良好的浏览器,则可以使用 array.indexOf(object) != -1 - Sam Soffes
另外,不要单独使用indexOf作为条件,因为第一个元素将返回0并将被评估为falsy - plus-
inArray 是一个函数的可怕名称,它返回元素的索引,和 -1 如果它不存在。我希望返回一个布尔值。 - Tim


更新:正如@orip在评论中提到的,链接的基准测试是在2008年完成的,因此结果可能与现代浏览器无关。但是,您可能需要它来支持非现代浏览器,因此它们可能尚未更新。总是为自己测试。

正如其他人所说,通过数组的迭代可能是最好的方法,但它 已被证实 减少 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

357
2017-10-25 22:49



不过要小心: stackoverflow.com/questions/237104/javascript-array-containsobj/... - MatrixFrog
“经证实”是一个强有力的词。 JS引擎不断改进,3年前测量的执行时间非常过时。 - orip
@Damir - 我同意。也许更改样本以使用indexOf(如果可用),这样人们盲目地复制粘贴此代码将获得最佳性能。 - orip
@cbmeeks是的,绝对需要关心。这可能就是一个例子 for (o in array) 通常在循环数组时不应该这样做... - Damir Zekić
最好的方法是检查[1,2,3] .indexOf(1)> -1 - Devin G Rhode


indexOf 也许,但它是“ECMA-262标准的JavaScript扩展;因此它可能不会出现在标准的其他实现中。”

例:

[1, 2, 3].indexOf(1) => 0
["foo", "bar", "baz"].indexOf("bar") => 1
[1, 2, 3].indexOf(4) => -1

AFAICS 微软呢  提供某种替代方案 对此,您可以在Internet Explorer(以及其他不支持的浏览器)中为数组添加类似的功能 indexOf如果你想,作为一个 快速谷歌搜索显示 (例如, 这个)。


156
2018-01-01 01:40



实际上,有一个示例是indexOf扩展的实现,用于在您链接到的developer.mozilla.org页面上不支持它的浏览器。 - Lloyd Cotten
实际上,如果你为不支持它的浏览器(即IE7)添加indexof到Array的原型,他们也会在循环遍历数组中的项时尝试循环这个函数。讨厌。 - CpILL
IE9现在支持这一点 - Liam
是否适用于检查对象。?我认为它不适用于Object - Himesh Aadeshara


ECMAScript 7介绍 Array.prototype.includes

它可以像这样使用:

[1, 2, 3].includes(2); // true
[1, 2, 3].includes(4); // false

它还接受可选的第二个参数 fromIndex

[1, 2, 3].includes(3, 3); // false
[1, 2, 3].includes(3, -1); // true

不像 indexOf,使用 严格的平等比较includes 比较使用 SameValueZero 平等算法。这意味着您可以检测数组是否包含a NaN

[1, 2, NaN].includes(NaN); // true

也不像 indexOfincludes 不会跳过缺失的索引:

new Array(5).includes(undefined); // true

目前它仍然是草案但可以 polyfilled使其适用于所有浏览器。


128
2018-03-24 04:59



IE和Microsfot Edge不支持(2015)(developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/...) - Adriano Resende
也相关, ES7兼容性表 (看起来像chrome现在支持它) - styfle
值得注意的是,Node 6+支持这一点 node.green - Ryan
是否适用于检查对象。?我认为它不适用于Object - Himesh Aadeshara


b 是价值,和 a 是数组。它回来了 true 要么 false

function(a, b) {
    return a.indexOf(b) != -1
}

96
2017-10-27 00:38



这部分我不明白“!!〜”。我认为这在IE8中不起作用,因为IE8不支持Array对象上的indexOf()。 - svlada
“〜”是一个运算符,它从一个数字中取消,反转和减去1。 indexOf如果失败则返回-1,因此“〜”将-1变为“0”。使用“!!”把数字变成boleans(!! 0 === false) - william malo
与!= - 1相同的表现 jsperf.com/indexof-check - aelgoa
只是有点呕吐,就在我嘴里。绝对不专业的代码。 - Michael Cole
我称缺乏关于布尔运算符不专业的影响的知识。但我同意可读代码的价值,我肯定会将其包含在一个明确标记的函数中。这正是大多数主要JS框架所做的。 - Fx32


这是一个 JavaScript 1.6兼容 实施 Array.indexOf

if (!Array.indexOf)
{
  Array.indexOf = [].indexOf ?
      function (arr, obj, from) { return arr.indexOf(obj, from); }:
      function (arr, obj, from) { // (for IE6)
        var l = arr.length,
            i = from ? parseInt( (1*from) + (from<0 ? l:0), 10) : 0;
        i = i<0 ? 0 : i;
        for (; i<l; i++) {
          if (i in arr  &&  arr[i] === obj) { return i; }
        }
        return -1;
      };
}

65
2017-09-13 17:32



这看起来很棒,但有点困惑:*第1和第3行的测试是否相同? *测试原型是不是更好,如果有必要,将函数添加到Array.prototype? - Avi Flax
它们并不相同。 [].indexOf 是一个简写 Array.prototype.indexOf。我们偏执防御Javascript程序员不惜一切代价避免扩展本机原型。 - Már Örlygsson
是不是 [].indexOf 创建一个新数组然后访问 indexOf, 同时 Array.prototype.indexOf只是直接访问原型? - alex
@alex是的 [].indexOf === Array.prototype.indexOf (在FireBug中尝试一下),但相反 [].indexOf !== Array.indexOf。 - Már Örlygsson


使用:

function isInArray(array, search)
{
    return array.indexOf(search) >= 0;
}

// Usage
if(isInArray(my_array, "my_value"))
{
    //...
}

46
2017-08-27 16:45



x ? true : false 通常是多余的。是这里。 - Ry-♦
@minitech为什么你说这是多余的? - Matías Cánepa
array.indexOf(search) >= 0 已经是一个布尔值。只是 return array.indexOf(search) >= 0。 - Ry-♦
@minitech非常感谢!实际上我不知道这样的建筑可以归还。 TIL新东西。 - Matías Cánepa
从字面上看,javascript中的任何构造都可以返回 - B T


扩展JavaScript Array 对象是一个非常糟糕的主意,因为您将新属性(您的自定义方法)引入其中 for-in 循环可以破坏现有的脚本。几年前的作者 原型 库必须重新设计他们的库实现才能删除这种东西。

如果您不需要担心与页面上运行的其他JavaScript的兼容性,那就去吧,否则,我会推荐更笨拙但更安全的独立功能解决方案。


38
2017-07-18 14:36



我不同意。出于这个原因,不应将for-in循环用于数组。当使用一个流行的js库时,使用for-in循环将会中断 - Tomas
这会被认为是猴子修补吗?大声笑有些人喜欢这样。 - cbmeeks


您可以使用 Array.prototype.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

这样做的好处是,一旦找到元素就会中止迭代,从而保存不必要的迭代周期。

有一点需要注意的是 some() 在所有js版本中都不存在:(来自网站)

有些被添加到第5版的ECMA-262标准中;就这样吧   可能不存在于标准的所有实现中

您可以在Node.js中使用它而不会出现任何问题。如果您需要支持所有浏览器,那么这个polyfill(来自同一个链接):

if (!Array.prototype.some)
{
  Array.prototype.some = function(fun /*, thisArg */)
  {
    'use strict';

    if (this === void 0 || this === null)
      throw new TypeError();

    var t = Object(this);
    var len = t.length >>> 0;
    if (typeof fun !== 'function')
      throw new TypeError();

    var thisArg = arguments.length >= 2 ? arguments[1] : void 0;
    for (var i = 0; i < len; i++)
    {
      if (i in t && fun.call(thisArg, t[i], i, t))
        return true;
    }

    return false;
  };
}

33
2018-01-07 12:49





一内胆:

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

21
2017-12-23 15:59



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


开箱即用,如果您多次拨打此电话,使用效率会大大提高 关联数组 使用哈希函数进行查找的Map。

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map


21
2018-06-15 01:15