如何检查数组是否在 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在数组中查找对象的问题。

答案

当前的浏览器有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 数组,则两者都在内部使用indexOf

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

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

从 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可能是,但是它是 “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的),如果你想, 快速谷歌搜索发现 (例如, 该一 )。

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相等算法的比较。这意味着您可以检测数组是否包含NaN

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

也不同于indexOfincludes不会跳过丢失的索引:

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

目前,它仍然是草稿,但可以对其进行多填充以使其在所有浏览器上均可使用。

最佳答案采用原始类型,但是如果您想确定数组是否包含具有某些特征的对象 ,则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

这样做的好处是,一旦找到元素,迭代就会中止,因此可以节省不必要的迭代周期。

此外,由于它返回布尔值,因此它非常适合if语句:

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

* 正如詹姆士(Jamess)在评论中指出的那样,在回答此问题时(2018 年 9 月Array.prototype.some() ,完全支持Array.prototype.some()caniuse.com 支持表

假设您已经定义了如下数组:

const array = [1, 2, 3, 4]

以下是检查其中是否存在3三种方法。它们全部返回truefalse

本机数组方法(自 ES2016 起)( 兼容性表

array.includes(3) // true

作为自定义数组方法(ES2016 之前)

// Prefixing the method with '_' to avoid name clashes
Object.defineProperty(Array.prototype, '_includes', { value: function (v) { return this.indexOf(v) !== -1 }})
array._includes(3) // true

功能简单

const includes = (a, v) => a.indexOf(v) !== -1
includes(array, 3) // true

这是Array.indexOfJavaScript 1.6 兼容实现:

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;
        };
}

采用:

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

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

扩展 JavaScript Array对象是一个非常糟糕的主意,因为您在for-in循环中引入了新属性(您的自定义方法) for-in这可能会破坏现有脚本。几年前, 原型库的作者不得不重新设计其库实现,以删除此类内容。

如果您不必担心与页面上运行的其他 JavaScript 的兼容性,请坚持下去,否则,我建议您使用更笨拙但更安全的独立功能解决方案。

开箱即用地思考一下,如果您多次进行此调用,那么使用关联数组 Map 来使用哈希函数进行查找的效率将大大提高。

https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Map