Bästa sättet att ta reda på om ett objekt finns i en JavaScript-array?


Vad är det bästa sättet att ta reda på om ett objekt finns i en array?

Det här är det bästa sättet jag känner till:

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

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

Svar #1

Från och med ECMAScript 2016 kan du använda includes()

arr.includes(obj);

Om du vill stödja IE eller andra äldre webbläsare:

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

REDIGERA: Detta kommer dock inte att fungera på IE6, 7 eller 8. Den bästa lösningen är att definiera det själv om det inte finns:

  1. Mozillas (ECMA-262) version:

       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. Daniel James version:

     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 version:

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

Svar #2

Om du använder jQuery:

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

För mer information: http://api.jquery.com/jQuery.inArray/

Svar #3

Först, implementera indexOf i JavaScript för webbläsare som inte redan har det. Till exempel, se Erik Arvidssons array extras (och även det tillhörande blogginlägget). Och sedan kan du använda indexOf utan att oroa dig för webbläsarstöd. Här är en något optimerad version av hans indexOf-implementation:

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

Det har ändrats för att lagra längden så att den inte behöver slå upp den vid varje iteration. Men skillnaden är inte stor. En mindre generell funktion kan vara snabbare:

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

Jag föredrar att använda standardfunktionen och lämna den här typen av mikrooptimering till när det verkligen behövs. Men om du är intresserad av mikrooptimering anpassade jag de benchmarktester som roosterononacid länkade till i kommentarerna, för att benchmarka sökning i arrayer. De är dock ganska grova, en fullständig undersökning skulle testa arrayer med olika typer, olika längder och att hitta objekt som förekommer på olika platser.

Svar #4

Om arrayen är osorterad finns det egentligen inget bättre sätt (förutom att använda det ovan nämnda indexOf, vilket jag tror motsvarar samma sak). Om arrayen är sorterad kan du göra en binärsökning, som fungerar så här:

  1. Välj mitt-elementet i arrayen.
  2. Är elementet du letar efter större än det element du valde? Om så är fallet har du tagit bort den nedre halvan av arrayen. Om det inte är det har du tagit bort den övre halvan.
  3. Välj det mellersta elementet av den återstående halvan av arrayen, och fortsätt som i steg 2, genom att eliminera halvor av den återstående arrayen. Så småningom kommer du antingen att hitta ditt element eller inte ha någon array kvar att söka igenom.

Binärsökning körs på en tid som är proportionell mot logaritmen av arrayens längd, så det kan vara mycket snabbare än att titta på varje enskild element.

Relaterade artiklar