Питання Як перевірити, чи містить масив об'єкт у JavaScript?


Який найкоротший і ефективний спосіб з'ясувати, чи містить масив JavaScript об'єкт?

Це єдиний шлях, яким я знаю, щоб це зробити:

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

Чи є кращий і більш стислий спосіб досягти цього?

Це дуже тісно пов'язано з записом переповнення Stack Найкращий спосіб знайти елемент у масиві 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, який буде оцінюватися як хибний, в той час як ~[1,2,3].indexOf(3) повернемо -3, яке буде оцінюватися як істина. - lordvlad
~ це не те, що ви хочете використовувати для перетворення в логічний, для цього вам потрібно !. Але в цьому випадку ви хочете перевірити рівність з -1, інакше ця функція може закінчитисяreturn [1,2,3].indexOf(3) === -1;  ~ це не бінарний, він інвертуватиме кожен біт значення індивідуально. - mcfedr
@ Іордвад [1,2,3].indexOf(4) буде насправді повернути -1. Як зазначив @mcfedr ~ є побітовий НЕ оператор, див. 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), обидва з яких використовуються indexOf внутрішньо, якщо пройшов масив JavaScript.

Деякі інші схеми пропонують подібні методи:

Зверніть увагу, що деякі системи виконують цю функцію як функцію, а інші додають цю функцію до прототипу масиву.


3650
2017-10-25 23:10



MooTools також містить Array.contains, що повертає логічне значення, яке схоже на справжнє питання тут. - Ryan Florence
Прототип теж є Array.include що повертає логічне значення - user102008
Якщо ви використовуєте хороший браузер, ви можете просто скористатись array.indexOf(object) != -1 - Sam Soffes
Крім того, не використовуйте indexOf як умову, оскільки перший елемент поверне 0 і буде оцінено як фальс - 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
@Дамир - я згоден. Можливо, змініть зразок, використовуючи indexOf, якщо такі є, так що люди, які копіюють цей код сліпо, отримають найкращу продуктивність. - orip
@cbmeeks так, турбота точно потрібна. Ймовірно, це так for (o in array) що не повинно бути зроблено, коли цикл через масив взагалі ... - Damir Zekić
Найкращий спосіб зробити це - перевірити, чи [1, 2, 3] .indexOf (1)> -1 - Devin G Rhode


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 показує (наприклад, цей)


156
2018-01-01 01:40



насправді, є приклад реалізації розширення indexOf для веб-переглядачів, які не підтримують його на сторінці developer.mozilla.org, з яким ви зв'язали. - Lloyd Cotten
насправді, якщо ви додаєте indexof до прототипу Array для веб-переглядачів, які не підтримують його (наприклад, IE7), вони також намагатимуться циклу над цією функцією при циклінгу через елементи масиву. неприємний - CpILL
IE9 тепер підтримує це - Liam
чи застосовується перевірка об'єкта.? Я не думаю, що це працює в разі об'єкта - 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

Також на відміну від indexOf, includes не пропускати відсутні показники:

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

В даний час це ще проект, але може бути поліфільованийщоб він працював у всіх браузерах.


128
2018-03-24 04:59



Не підтримується для IE і Microsfot Edge (2015) (developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/...) - Adriano Resende
Також актуально, ES7 таблиця сумісності (начебто хром підтримує його зараз) - styfle
Варто відзначити, що це підтримується в Node 6+, відповідно до node.green - Ryan
чи застосовується перевірка об'єкта.? Я не думаю, що це працює в разі об'єкта - Himesh Aadeshara


b це значення, і a це масив. Це повертається true або false:

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

96
2017-10-27 00:38



Ця частина я не розумію "!! ~". І я думаю, що це не буде працювати в IE8, тому що IE8 не підтримує indexOf () в об'єкті Array. - svlada
"~" - це оператор, який повертає, інвертує і вираховує 1 з числа. indexOf повертає -1, якщо він не працює, тому "~" перетворює -1 в "0". використовуючи "!!" перетворює числа в bleans (!! 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 для масивів. Використання циклів for-in буде порушене при використанні однієї з популярних бібліотек js - Tomas
Чи буде це вважати лакування мавпи? lol Деякі люди це подобаються. - cbmeeks


Ви можете використовувати Масив.прототип.симе ()

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: (з веб-сайту)

деякі були додані до стандарту ECMA-262 у 5-му випуску; як такий це   може не бути присутнім у всіх реалізаціях стандарту

Ви можете використовувати його в Node.js без проблем. Якщо вам потрібно підтримувати всі веб-переглядачі, існує така поліфіль (з тієї ж посилання):

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