Pytanie Jak sprawdzić, czy tablica zawiera obiekt w JavaScript?


Jaki jest najbardziej zwięzły i skuteczny sposób sprawdzenia, czy tablica JavaScript zawiera obiekt?

Jest to jedyny sposób, w jaki to robię:

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

Czy istnieje lepszy i bardziej zwięzły sposób, aby to osiągnąć?

Jest to bardzo blisko związane z pytaniem Stack Overflow Najlepszy sposób na znalezienie przedmiotu w tablicy JavaScript? który odnosi się do znajdowania obiektów w tablicy za pomocą indexOf.


3226
2017-10-25 22:14


pochodzenie


po prostu przetestowane: Twoja droga jest najszybsza w różnych przeglądarkach: jsperf.com/find-element-in-obj-vs-array/2 (oprócz wstępnego zapisywania długości w zmiennej) podczas korzystania z indexOf (jak w $ .inArray) jest znacznie wolniejsze - Jörn Berkefeld
wielu odpowiedziało, że Array # indexOf to najlepszy wybór tutaj. Ale jeśli chcesz coś, co można poprawnie rzutować na Boolean, użyj tego: ~[1,2,3].indexOf(4) zwróci 0, które będą oceniać jako false, podczas gdy ~[1,2,3].indexOf(3) zwróci -3, co zostanie ocenione jako prawdziwe. - lordvlad
~ nie jest tym, czego chcesz użyć do konwersji na wartość boolowską, ponieważ jest to potrzebne !. Ale w tym przypadku chcesz sprawdzić równość przez -1, s o funkcja może się skończyćreturn [1,2,3].indexOf(3) === -1;  ~ nie jest binarnym, odwróci każdy bit wartości indywidualnie. - mcfedr
@Iordvlad [1,2,3].indexOf(4) rzeczywiście return -1. Jak zauważył @mcfedr, ~ jest operator bitowy-NOTpatrz ES5 11.4.8. Rzecz w tym, że od binarnej reprezentacji -1 składa się tylko z 1, jest uzupełnieniem 0, który ocenia jako fałszywy. Dopełnienie jakiejkolwiek innej liczby będzie niezerowe, a więc prawdziwe. Więc, ~ działa dobrze i jest często używany w połączeniu z indexOf. - mknecht
Tytuł jest mylący. Gdzie jest [[1,2],[3,4]].includes([3,4]) ? - mplungjan


Odpowiedzi:


Obecne przeglądarki mają Array#includes, co robi dokładnie że, jest szeroko wspieranyi ma polyfill dla starszych przeglądarek.

> ['joe', 'jane', 'mary'].includes('jane');
true 

Możesz także użyć Array#indexOf, która jest mniej bezpośrednia, ale nie wymaga oprogramowania Polyfills dla nieaktualnych przeglądarek.

oferty jQuery $.inArray, który jest funkcjonalnie równoważny Array#indexOf.

underscore.js, biblioteka narzędzi JavaScript, oferty _.contains(list, value), Alias _.include(list, value), z których oba korzystają indeks wewnętrznie, jeśli przeszedł tablicę JavaScript.

Niektóre inne środowiska oferują podobne metody:

Zauważ, że niektóre frameworki implementują to jako funkcję, podczas gdy inne dodają funkcję do prototypu macierzy.


3650
2017-10-25 23:10



MooTools ma również Array.contains, który zwraca boolean, co brzmi jak prawdziwe pytanie tutaj. - Ryan Florence
prototyp też ma Array.include która zwraca wartość logiczną - user102008
Jeśli korzystasz z dobrej przeglądarki, możesz po prostu użyć array.indexOf(object) != -1 - Sam Soffes
Nie używaj też samego indexOf jako warunku, ponieważ pierwszy element zwróci 0 i zostanie oceniony jako falsy - plus-
inArray to straszna nazwa funkcji, która zwraca indeks elementu, i -1 jeśli nie istnieje. Spodziewam się zwrotu wartości boolowskiej. - Tim


Aktualizacja: Jak wspomina @orip w komentarzach, powiązany test porównawczy został wykonany w 2008 roku, więc wyniki mogą nie być odpowiednie dla nowoczesnych przeglądarek. Prawdopodobnie jednak potrzebujesz tego do obsługi nie-nowoczesnych przeglądarek i prawdopodobnie nie były one aktualizowane od tego czasu. Zawsze sprawdzaj sam.

Jak powiedzieli inni, iteracja przez macierz jest prawdopodobnie najlepszym sposobem, ale to zostało udowodnione to maleje while loop to najszybszy sposób na iterację w JavaScript. Więc możesz chcieć przepisać swój kod w następujący sposób:

function contains(a, obj) {
    var i = a.length;
    while (i--) {
       if (a[i] === obj) {
           return true;
       }
    }
    return false;
}

Oczywiście, możesz równie dobrze przedłużyć prototyp Array:

Array.prototype.contains = function(obj) {
    var i = this.length;
    while (i--) {
        if (this[i] === obj) {
            return true;
        }
    }
    return false;
}

A teraz możesz po prostu użyć następującego:

alert([1, 2, 3].contains(2)); // => true
alert([1, 2, 3].contains('2')); // => false

357
2017-10-25 22:49



Ale bądź ostrożny: stackoverflow.com/questions/237104/javascript-array-containsobj/... - MatrixFrog
"Udowodnione" to mocne słowo. Silniki JS stale się poprawiają, a czas wykonania mierzony 3 lata temu jest strasznie nieaktualny. - orip
@Damir - Zgadzam się. Być może zmień próbkę, aby użyć indexOf, jeśli jest dostępna, aby ludzie kopiowali - wklejając ten kod na ślepo, uzyskają najlepszą możliwą wydajność. - orip
@ cbmeeks, ta opieka jest zdecydowanie potrzebna. Prawdopodobnie był to przypadek for (o in array) co nie powinno być robione, gdy ogólnie zapętla się tablica ... - Damir Zekić
Najlepszym sposobem na to jest sprawdzenie, czy [1, 2, 3] .indexOf (1)> -1 - Devin G Rhode


indexOf może, ale jest to "rozszerzenie JavaScript do standardu ECMA-262, jako takie może nie być obecne w innych implementacjach standardu."

Przykład:

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

AFAICS Microsoft to robi nie zaoferować jakąś alternatywę do tego, ale możesz dodać podobną funkcjonalność do tablic w Internet Explorerze (i innych przeglądarkach, które nie obsługują indexOf) jeśli chcesz, jako szybkie wyszukiwanie w Google ujawnia (na przykład, ten).


156
2018-01-01 01:40



w rzeczywistości istnieje przykład implementacji rozszerzenia indexOf dla przeglądarek, które nie obsługują go na stronie developer.mozilla.org, do której jesteś podłączony. - Lloyd Cotten
w rzeczywistości, jeśli dodasz indexof do prototypu Array dla przeglądarek, które go nie obsługują (tj. IE7), spróbują również zapętlić tę funkcję podczas przechodzenia przez elementy w tablicy. paskudny. - CpILL
IE9 teraz obsługuje to - Liam
czy ma zastosowanie przy sprawdzaniu obiektu? nie sądzę, że działa w przypadku obiektu - Himesh Aadeshara


ECMAScript 7 wprowadza Array.prototype.includes.

Może być używany w następujący sposób:

[1, 2, 3].includes(2); // true
[1, 2, 3].includes(4); // false

Akceptuje także opcjonalny drugi argument fromIndex:

[1, 2, 3].includes(3, 3); // false
[1, 2, 3].includes(3, -1); // true

w odróżnieniu indexOf, który używa Ścisłe porównanie równości, includes porównuje użycie SameValueZero algorytm równości. Oznacza to, że możesz wykryć, czy tablica zawiera NaN:

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

Również w przeciwieństwie do indexOf, includes nie pomija brakujących indeksów:

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

Obecnie jest to nadal wersja robocza, ale może być polyfilledaby działał we wszystkich przeglądarkach.


128
2018-03-24 04:59



Nieobsługiwane przez IE i Microsfot Edge (2015) (developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/...) - Adriano Resende
Również istotne, Tabela zgodności ES7 (wygląda na to, że chrome obsługuje teraz) - styfle
Warto zauważyć, że jest to obsługiwane w Node 6+, zgodnie z node.green - Ryan
czy ma zastosowanie przy sprawdzaniu obiektu? nie sądzę, że działa w przypadku obiektu - Himesh Aadeshara


b jest wartością i a jest tablicą. Powraca true lub false:

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

96
2017-10-27 00:38



W tej części nie rozumiem "!!". I myślę, że to nie zadziała w IE8, ponieważ IE8 nie obsługuje indexOf () na obiekcie Array. - svlada
"~" to operator, który kondygnuje, odwraca i odejmuje 1 od liczby. indexOf zwraca -1, jeśli się nie powiedzie, więc "~" zmienia -1 na "0". za pomocą "!!" zamienia liczby w boleany (!! 0 === false) - william malo
taka sama wydajność jak! = - 1 jsperf.com/indexof-check - aelgoa
Tylko odrobina zwymiotowania, prosto w moje usta. Absolutnie nieprofesjonalny kod. - Michael Cole
Nazwałbym brak wiedzy o skutkach nieprofesjonalnych operatorów boolowskich. Ale zgadzam się co do wartości czytelnego kodu, z pewnością zawinęłbym to w wyraźnie oznaczoną funkcję. I właśnie to robi większość dużych frameworków JS. - Fx32


Tutaj jest Obsługa JavaScript 1.6 Wdrożenie 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



To wygląda świetnie, ale trochę mylone: ​​* Czy testy na liniach 1 i 3 nie są równoważne? * Czy nie byłoby lepiej przetestować prototyp i jeśli to konieczne, dodać funkcję do Array.prototype? - Avi Flax
Nie są one równe. [].indexOf jest skrótem dla Array.prototype.indexOf. My, programiści paranoidalnie defensywni Javascript, unikamy rozszerzania rodzimych prototypów za wszelką cenę. - Már Örlygsson
Nie jest [].indexOf tworzenie nowej tablicy, a następnie uzyskiwanie dostępu indexOf, podczas Array.prototype.indexOf uzyskujesz bezpośredni dostęp do prototypu? - alex
@alex tak [].indexOf === Array.prototype.indexOf (wypróbuj w FireBug), ale na odwrót [].indexOf !== Array.indexOf. - Már Örlygsson


Posługiwać się:

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 jest zwykle zbędny. To jest tutaj. - Ry-♦
@minitech Dlaczego mówisz, że jest zbędny? - Matías Cánepa
array.indexOf(search) >= 0 jest już boolowskie. Właśnie return array.indexOf(search) >= 0. - Ry-♦
@ Minitech dobrze dzięki! Właściwie nie wiedziałem, że taka konstrukcja może zostać zwrócona. TIL coś nowego. - Matías Cánepa
Dosłownie każdy konstrukt w javascript może zostać zwrócony - B T


Rozszerzanie JavaScript Array obiekt jest naprawdę złym pomysłem, ponieważ wprowadzasz nowe właściwości (własne metody) do for-in pętle, które mogą łamać istniejące skrypty. Kilka lat temu autorzy Prototyp biblioteka musiała przebudować swoją implementację biblioteki, aby usunąć właśnie takie rzeczy.

Jeśli nie musisz się martwić o kompatybilność z innym JavaScriptem uruchomionym na twojej stronie, idź za nim, w przeciwnym razie poleciłbym bardziej niezręczne, ale bezpieczniejsze rozwiązanie wolnostojące.


38
2017-07-18 14:36



Nie zgadzam się. Pętle typu "to-in" nie powinny być używane do tablic z tego właśnie powodu. Używanie pętli for-in zostanie przerwane podczas korzystania z jednej z popularnych bibliotek js - Tomas
Czy to byłoby uważane za łatanie małpy? lol Niektórzy ludzie to lubią. - cbmeeks


Możesz użyć 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

Do tego dochodzi fakt, że iteracja jest przerywana po znalezieniu elementu, więc niepotrzebne cykle iteracji są zapisywane.

Jedna rzecz do zapamiętania jest taka some() nie występuje we wszystkich wersjach js: (ze strony internetowej)

niektóre zostały dodane do standardu ECMA-262 w piątej edycji; jako taki   może nie być obecny we wszystkich implementacjach standardu

Możesz go używać w Node.js bez żadnego problemu. Jeśli potrzebujesz obsługi wszystkich przeglądarek, to jest ta polyfill (z tego samego linku):

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