Вопрос: Как проверить, содержит ли массив объект в JavaScript?


Каков наиболее сжатый и эффективный способ узнать, содержит ли массив JavaScript объект?

Это единственный способ, которым я это знаю:

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

Есть ли лучший и более сжатый способ сделать это?

Это очень тесно связано с вопросом о переполнении стека Лучший способ найти элемент в массиве JavaScript? который рассматривает поиск объектов в массиве, используя indexOf,


3161


источник


Ответы:


Текущие браузеры Array#includes, что делает в точку что, широко поддерживается , и имеет polyfill для старых браузеров.

Вы также можете использовать Array#indexOf, который является менее прямым, но не требует наличия полифилов для устаревших браузеров.

Предложения jQuery $.inArray, что функционально эквивалентно Array#indexOf,

underscore.js , утилита JavaScript, предлагает _.contains(list, value), псевдоним _.include(list, value), оба из которых используют индекс внутренне, если передан массив JavaScript.

Некоторые другие структуры предлагают аналогичные методы:

Обратите внимание, что некоторые структуры реализуют это как функцию, а другие добавляют функцию к прототипу массива.


3602



Обновление. Как упоминает @orip в комментариях, связанный бенчмарк был выполнен в 2008 году, поэтому результаты могут не иметь отношения к современным браузерам. Однако вам, вероятно, понадобится это, чтобы поддерживать несовременные браузеры в любом случае, и, вероятно, они не обновлялись с тех пор. Всегда проверяйте себя.

Как говорили другие, итерация через массив, вероятно, является лучшим способом, но это доказано что уменьшение whileloop - это самый быстрый способ итерации в 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

355



indexOfвозможно, но это «расширение JavaScript стандарта ECMA-262, поэтому оно может отсутствовать в других реализациях стандарта».

Пример:

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

AFAICS Microsoft делает не предлагают какую-то альтернативу к этому, но вы можете добавить аналогичную функциональность в массивы в Internet Explorer (и другие браузеры, которые не поддерживают indexOf), если вы хотите, как быстрый поиск Google показывает (например, вот этот ).


149



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

Кроме того, в отличие от indexOf, includesне пропускает отсутствующие индексы:

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

В настоящее время это все еще проект, но может быть polyfilled чтобы он работал на всех браузерах.


125



b is the value, and a is the array. It returns true or false:

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

95



Here's a JavaScript 1.6 compatible implementation of 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



Use:

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

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

46



Extending the JavaScript Array object is a really bad idea because you introduce new properties (your custom methods) into for-in loops which can break existing scripts. A few years ago the authors of the Prototype library had to re-engineer their library implementation to remove just this kind of thing.

If you don't need to worry about compatibility with other JavaScript running on your page, go for it, otherwise, I'd recommend the more awkward, but safer free-standing function solution.


38



You can use 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

Upside to this is that the iteration is aborted once the element is found so unnecessary iteration cycles are saved.

One thing to note is that some() is not present in all js versions: (from the website)

some was added to the ECMA-262 standard in the 5th edition; as such it may not be present in all implementations of the standard

You can use it in Node.js without any issue. If you need to support all browsers then there's this polyfill (from the same link):

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

32



One-liner:

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

21



Thinking out of the box for a second, if you are making this call many many times, it is vastly more efficient to use an associative array a Map to do lookups using a hash function.

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


20



I use the following:

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

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

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

19