Лучший способ узнать, находится ли элемент в массиве JavaScript? [дубликат]

этот вопрос уже есть ответ здесь:

каков наилучший способ найти, если объект находится в массиве?

Это лучший способ, который я знаю:

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

include([1,2,3,4], 3); // true
include([1,2,3,4], 6); // undefined

8 ответов


начиная с ECMAScript 2016 вы можете использовать includes()

arr.includes(obj);

если вы хотите поддерживать IE или другие устаревшие браузеры:

function include(arr,obj) {
    return (arr.indexOf(obj) != -1);
}

изменить: Это не будет работать на IE6, 7 или 8 хотя бы. Лучший обходной путь-определить его самостоятельно, если его нет:

  1. в Mozilla (ECMA-262) версия:

      if (!Array.prototype.indexOf)
      {
    
           Array.prototype.indexOf = function(searchElement /*, fromIndex */)
    
        {
    
    
        "use strict";
    
        if (this === void 0 || 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 > 0)
        {
          n = Number(arguments[1]);
          if (n !== n)
            n = 0;
          else if (n !== 0 && n !== (1 / 0) && n !== -(1 / 0))
            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;
      };
    
    }
    
  2. Дэниел Джеймс'ы версия:

    if (!Array.prototype.indexOf) {
      Array.prototype.indexOf = function (obj, fromIndex) {
        if (fromIndex == null) {
            fromIndex = 0;
        } else if (fromIndex < 0) {
            fromIndex = Math.max(0, this.length + fromIndex);
        }
        for (var i = fromIndex, j = this.length; i < j; i++) {
            if (this[i] === obj)
                return i;
        }
        return -1;
      };
    }
    
  3. roosteronacid'S версия:

    Array.prototype.hasObject = (
      !Array.indexOf ? function (o)
      {
        var l = this.length + 1;
        while (l -= 1)
        {
            if (this[l - 1] === o)
            {
                return true;
            }
        }
        return false;
      } : function (o)
      {
        return (this.indexOf(o) !== -1);
      }
    );
    

Если вы используете jQuery:

$.inArray(5 + 5, [ "8", "9", "10", 10 + "" ]);

дополнительные сведения: http://api.jquery.com/jQuery.inArray/


во-первых, реализовать indexOf в JavaScript для браузеров, которые еще не имеют его. Например, см. массив Эрика Арвидссона дополнительно (кроме того,связанный пост в блоге). И тогда вы можете использовать indexOf, не беспокоясь о поддержке браузеров. Вот немного оптимизированная версия его indexOf реализация:

if (!Array.prototype.indexOf) {
    Array.prototype.indexOf = function (obj, fromIndex) {
        if (fromIndex == null) {
            fromIndex = 0;
        } else if (fromIndex < 0) {
            fromIndex = Math.max(0, this.length + fromIndex);
        }
        for (var i = fromIndex, j = this.length; i < j; i++) {
            if (this[i] === obj)
                return i;
        }
        return -1;
    };
}

он изменен, чтобы сохранить длину, так что ему не нужно искать ее каждую итерацию. Но разница невелика. Минус функция общего назначения может быть быстрее:

var include = Array.prototype.indexOf ?
    function(arr, obj) { return arr.indexOf(obj) !== -1; } :
    function(arr, obj) {
        for(var i = -1, j = arr.length; ++i < j;)
            if(arr[i] === obj) return true;
        return false;
    };

Я предпочитаю использовать стандартную функцию и оставлять такую микро-оптимизацию, когда она действительно нужна. Но если вы заинтересованы в микро-оптимизации, я адаптировал критерии что roosterononacid связан с в комментариях, чтобы тест поиск в массивах. Они довольно грубые, хотя полное исследование будет тестировать массивы с разными типами, разной длиной и находить объекты, которые встречаются в разных местах.


Если массив несортирован, на самом деле нет лучшего способа (кроме использования вышеупомянутого indexOf, который, я думаю, составляет то же самое). Если массив отсортирован, вы можете выполнить двоичный поиск, который работает следующим образом:

  1. выбрать средний элемент массива.
  2. - Это элемент, который вы ищете больше, чем элемент, который вы выбрали? Если это так,вы исключили нижнюю половину массива. Если это не так, вы устранили верхний половина.
  3. выберите средний элемент оставшейся половины массива и продолжите, как на Шаге 2, исключив половины оставшегося массива. В конце концов вы либо найдете свой элемент, либо у вас не останется массива для просмотра.

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


предполагая, что .indexOf() осуществляется

Object.defineProperty( Array.prototype,'has',
{
    value:function(o, flag){
    if (flag === undefined) {
        return this.indexOf(o) !== -1;
    } else {   // only for raw js object
        for(var v in this) {
            if( JSON.stringify(this[v]) === JSON.stringify(o)) return true;
        }
        return false;                       
    },
    // writable:false,
    // enumerable:false
})

!!! не делайте Array.prototype.has=function(){... потому что вы добавите перечисляемый элемент в каждый массив, и JS будет сломан.

//use like          
[22 ,'a', {prop:'x'}].has(12) // false
["a","b"].has("a") //  true

[1,{a:1}].has({a:1},1) // true
[1,{a:1}].has({a:1}) // false

использование 2-го arg (флаг) заставляет сравнение по значению вместо ссылки


Это зависит от вашей цели. Если вы программируете для Интернета, избегайте indexOf, Он не поддерживается Internet Explorer 6 (Многие из них все еще используются!), или сделать условное использование:

if (yourArray.indexOf !== undefined) result = yourArray.indexOf(target);
else result = customSlowerSearch(yourArray, target);

indexOf вероятно, закодирован в собственном коде, поэтому он быстрее, чем все, что вы можете сделать в JavaScript (кроме двоичного поиска/дихотомии, если массив подходит). Примечание: это вопрос вкуса, но я бы сделал return false; В конце вашей процедуры, чтобы вернуть true Boolean...


вот некоторые мета-знания для вас - если вы хотите знать, что вы можете сделать с массивом, проверьте документацию - вот страница выбора для Mozilla

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

там вы увидите ссылку на indexOf, добавленную в Javascript 1.6


надежный способ проверить, является ли объект массивом в javascript, подробно описан здесь:

вот две функции из xa.js рамки, которые я прикрепляю к ‘’. Они должны помочь вам правильно определять массивы.

var utils = {};

/**
 * utils.isArray
 *
 * Best guess if object is an array.
 */
utils.isArray = function(obj) {
     // do an instanceof check first
     if (obj instanceof Array) {
         return true;
     }
     // then check for obvious falses
     if (typeof obj !== 'object') {
         return false;
     }
     if (utils.type(obj) === 'array') {
         return true;
     }
     return false;
 };

/**
 * utils.type
 *
 * Attempt to ascertain actual object type.
 */
utils.type = function(obj) {
    if (obj === null || typeof obj === 'undefined') {
        return String (obj);
    }
    return Object.prototype.toString.call(obj)
        .replace(/\[object ([a-zA-Z]+)\]/, '').toLowerCase();
};

если вы хотите проверить, находится ли объект в массиве, я бы также включил этот код:

/**
 * Adding hasOwnProperty method if needed.
 */
if (typeof Object.prototype.hasOwnProperty !== 'function') {
    Object.prototype.hasOwnProperty = function (prop) {
        var type = utils.type(this);
        type = type.charAt(0).toUpperCase() + type.substr(1);
        return this[prop] !== undefined
            && this[prop] !== window[type].prototype[prop];
    };
}

и, наконец, эта функция in_array:

function in_array (needle, haystack, strict) {
    var key;

    if (strict) {
        for (key in haystack) {
            if (!haystack.hasOwnProperty[key]) continue;

            if (haystack[key] === needle) {
                return true;
            }
        }
    } else {
        for (key in haystack) {
            if (!haystack.hasOwnProperty[key]) continue;

            if (haystack[key] == needle) {
                return true;
            }
        }
    }

    return false;
}