Как лучше всего определить, находится ли объект в массиве?
Это лучший способ, который я знаю:
function include(arr, obj) {
for (var i = 0; i < arr.length; i++) {
if (arr[i] == obj) return true;
}
}
console.info(include([1, 2, 3, 4], 3)); // true
console.info(include([1, 2, 3, 4], 6)); // undefined2 вещи: 1. 'include' - плохое название для функции, которая ничего не меняет. Это особенно плохо для функции, которая просто возвращает логическое значение. 2.) Вам нужно добавить «return (false);» перед окончанием функции.
с ECMAScript 2016 вы можете использовать функцию Array.prototype.includes: myArray.includes (3); // правда
В ES6 вы можете сделать что-то вроде array.find (лямбда-функция), например: [1, 2, 3,4,5] .find (x => x == 3). если элемент найден, он возвращается, иначе возвращается undefined
arr.some (element => element === obj); some - лучший способ, потому что когда он находит элемент, а затем разрывает цикл.



![Безумие обратных вызовов в javascript [JS]](https://i.imgur.com/WsjO6zJb.png)


Начиная с ECMAScript 2016 вы можете использовать includes()
arr.includes(obj);
Если вы хотите поддерживать IE или другие старые браузеры:
function include(arr,obj) {
return (arr.indexOf(obj) != -1);
}
Обновлено: Однако это не будет работать в IE6, 7 или 8. Лучшее решение - определить его самостоятельно, если его нет:
Версия 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;
};
}
Версия Дэниел Джеймс:
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;
};
}
Версия петушок:
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);
}
);
Мне любопытно, почему ваша версия функции Mozilla так отличается от веб-сайта, на который вы ссылаетесь. Вы сами его модифицировали или это просто старая версия или что-то в этом роде?
@Shenjoku: "ответил 27 сен '08 в 15:45"
Ну вот и мой ответ, ха-ха. Я не могу сказать, есть ли более старая версия, просто взглянув на веб-сайт Mozilla, поэтому я не был уверен. Не то чтобы это имело значение, просто любопытство. В любом случае это все еще было полезно, так что вы получите положительный голос;)
@Vinko Vrsalovic Да, это хорошее решение, но вам следует скрыть встроенную реализацию функции indexOf (), которая возвращает -1 с помощью оператора ~: function include (arr, obj) {return !! (~ arr.indexOf (obj)); }
но, поскольку когда indexOf совместим с IE, потому что я обнаружил, что он совместим с IE w3schools.com/jsref/jsref_indexof.asp
@VinkoVrsalovic, как мне изменить эту функцию function include (arr, obj) {return (arr.indexOf (obj)! = -1); } Чтобы вернуть истину или ложь при передаче нескольких значений, например, двух строк? : D
Если массив не отсортирован, лучшего способа на самом деле нет (кроме использования вышеупомянутого indexOf, что, как мне кажется, равносильно тому же). Если массив отсортирован, вы можете выполнить двоичный поиск, который работает следующим образом:
Двоичный поиск выполняется по времени, пропорциональному логарифму длины массива, поэтому он может быть намного быстрее, чем просмотр каждого отдельного элемента.
Вы, вероятно, должны упомянуть, что этот подход будет быстрее работать с большими отсортированными массивами, чем с маленькими.
почему это будет медленнее на меньших массивах?
@vidstige: он имеет в виду, что он хорошо масштабируется, но не обязательно самый быстрый для небольших входов.
Это выполняется за O (lg n), а не за O (n), что намного более масштабируемо.
Вот некоторые мета-знания для вас - если вы хотите знать, что вы можете делать с массивом, проверьте документацию - вот страница Array для Mozilla
https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Array
Там вы увидите ссылку на indexOf, добавленную в Javascript 1.6.
Странный URL-адрес руководства, содержащего информацию о Javascript 1.8 и более поздних версиях! :)
это не касается массивов объектов, о которых спрашивал автор
@VinkoVrsalovic: URL-адрес изменился на developer.mozilla.org/en-US/docs/JavaScript/Reference/…
Это зависит от вашей цели. Если вы программируете для Интернета, избегайте indexOf, он не поддерживается Internet Explorer 6 (многие из них все еще используются!) Или используйте условное использование:
if (yourArray.indexOf !== undefined) result = yourArray.indexOf(target);
else result = customSlowerSearch(yourArray, target);
indexOf, вероятно, закодирован в собственном коде, поэтому он быстрее, чем все, что вы можете сделать в JavaScript (кроме двоичного поиска / дихотомии, если массив подходит).
Примечание: это вопрос вкуса, но я бы сделал return false; в конце вашей процедуры, чтобы вернуть истинное логическое значение ...
ха ... Мне страшно подумать, что на данный момент все еще существует клиент IE6 ...
не должно быть «по состоянию на 2008 год», как на странице википедии, чтобы люди знали, что это утверждение, безусловно, устарело
@ allan.simon Посмотрите на мой значок (и статистику) внизу моего ответа. Чуть выше есть «ответ 27 сен. 2008 в 16:28». Это называется датой, и люди, привыкшие к Stack Overflow, смотрят на эти даты, чтобы получать ответы с долей скептицизма ... Тем не менее, в моей местной публичной библиотеке на компьютерах все еще установлен IE6! (но, к счастью, кто-то установил Chrome!)
Во-первых, внедрите 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 в комментариях, в тестовый поиск в массивах. Хотя они довольно грубые, полное расследование позволит протестировать массивы разных типов, разной длины и найти объекты, которые встречаются в разных местах.
Примеры кода, на которые вы ссылаетесь, работают медленно на больших массивах. См. Комментарии в моем примере реализации функции hasItem ().
Взгляните на эти тесты: blogs.sun.com/greimer/resource/loop-test.htm For-loop медленные. Но я думаю, что массивы, используемые в тестах, довольно большие :)
Я согласен. Я тоже довольно прагматичен. Но в случае оптимизации самых основ языка, я думаю, что это хороший дизайн, чтобы реализовать функциональность, максимально эффективную с точки зрения производительности.
используйте mozilla Array.indexOf polyfill: developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
Если вы используете jQuery:
$.inArray(5 + 5, [ "8", "9", "10", 10 + "" ]);
Для получения дополнительной информации: http://api.jquery.com/jQuery.inArray/
Обратите внимание, что inArray неправильно употреблено, потому что он не возвращает логическое значение - он возвращает индекс первого найденного элемента. Поэтому, если вы проверяете, существует ли элемент, вы должны использовать if (-1 != $.inArray(...)) ....
Полезно, но я не думаю, что здесь правильный ответ. На мой взгляд, вопрос помечен как "javascript", что означает "ваниль". :)
Здесь подробно описан надежный способ проверить, является ли объект массивом в javascript:
Вот две функции из фреймворка xa.js, которые я прикрепляю к «контейнеру» utils = {}. Это должно помочь вам правильно обнаруживать массивы.
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;
}
Хотя это теоретически может ответить на вопрос, было бы предпочтительнее, чтобы включить сюда основные части ответа и предоставить ссылку для справки. Кроме того, когда вы копируете / вставляете один и тот же ответ только по ссылке сразу на несколько очень старых вопросов, это просто выглядит как спам.
Извините, Билл, я действительно не имел в виду, что это похоже на спам, и просто пытался обновить несколько старых вопросов по этой теме. Я отредактировал сообщение здесь, чтобы включить фактический ответ вместо ссылки.
@ Билл, на самом деле перечитываю вопрос, это даже не отвечает на него. Я, должно быть, ошибся.
[] .has (объект)
предполагая, что .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-го аргумента (флага) вызывает сравнение по значению вместо ссылки
сравнение сырых объектов
[o1].has(o2,true) // true if every level value is same
См .: stackoverflow.com/a/25765186/1320932