javascript - Bestem om et array inneholder en verdi


Jeg må finne ut om en verdi finnes i en matrise.

Jeg bruker følgende funksjon:

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

Den ovennevnte funksjonen returnerer alltid false.

Arrayverdiene og funksjonskallet er som følger:

arrValues = ["Sam","Great", "Sample", "High"]
alert(arrValues.contains("Sam"));

Svar #1

jQuery har en hjelpefunksjon for dette:

$.inArray(value, array)

Returnerer indeksen til value i array. Returnerer -1 hvis array ikke inneholder value.

Se også Hvordan sjekker jeg om et array inkluderer et objekt i JavaScript?

Svar #2

var contains = function(needle) {
    // Per spec, the way to identify NaN is that it is not equal to itself
    var findNaN = needle !== needle;
    var indexOf;

    if(!findNaN && typeof Array.prototype.indexOf === 'function') {
        indexOf = Array.prototype.indexOf;
    } else {
        indexOf = function(needle) {
            var i = -1, index = -1;

            for(i = 0; i < this.length; i++) {
                var item = this[i];

                if((findNaN && item !== item) || item === needle) {
                    index = i;
                    break;
                }
            }

            return index;
        };
    }

    return indexOf.call(this, needle) > -1;
};

Du kan bruke det slik:

var myArray = [0,1,2],
    needle = 1,
    index = contains.call(myArray, needle); // true

CodePen-validering/bruksområde

Svar #3

Dette er generelt hva indexOf()-metoden er til for. Du ville si:

return arrValues.indexOf('Sam') > -1

Svar #4

Array.prototype.includes()

I ES2016 finnes Array.prototype.includes().

Metoden includes() avgjør om et array inneholder et bestemt element, og returnerer true eller false etter behov.

Eksempel

["Sam", "Great", "Sample", "High"].includes("Sam"); // true

Støtte

Ifølge kangax og MDN støttes følgende plattformer:

  • Chrome 47
  • Edge 14
  • Firefox 43
  • Opera 34
  • Safari 9
  • Node 6

Støtte kan utvides ved å bruke Babel (ved å bruke babel-polyfill) eller core-js. MDN tilbyr også en polyfill:

if (![].includes) {
  Array.prototype.includes = function(searchElement /*, fromIndex*/ ) {
    'use strict';
    var O = Object(this);
    var len = parseInt(O.length) || 0;
    if (len === 0) {
      return false;
    }
    var n = parseInt(arguments[1]) || 0;
    var k;
    if (n >= 0) {
      k = n;
    } else {
      k = len + n;
      if (k < 0) {k = 0;}
    }
    var currentElement;
    while (k < len) {
      currentElement = O[k];
      if (searchElement === currentElement ||
         (searchElement !== searchElement && currentElement !== currentElement)) {
        return true;
      }
      k++;
    }
    return false;
  };
}

Svar #5

Det er nesten alltid tryggere å bruke et bibliotek som lodash rett og slett på grunn av alle problemene med kompatibilitet på tvers av nettlesere og effektivitet.

Effektivitet fordi du kan være sikker på at på et gitt tidspunkt vil et svært populært bibliotek som underscore ha den mest effektive metoden for å utføre en nyttefunksjon som denne.

_.includes([1, 2, 3], 3); // returns true

Hvis du er bekymret for volumet som legges til applikasjonen din ved å inkludere hele biblioteket, bør du vite at du kan inkludere funksjonalitet separat:

var includes = require('lodash/collections/includes');

MERK: Med eldre versjoner av lodash, var dette _.contains() i stedet for _.includes().

Svar #6

Siden ECMAScript6 kan man bruke Set:

var myArray = ['A', 'B', 'C'];
var mySet = new Set(myArray);
var hasB = mySet.has('B'); // true
var hasZ = mySet.has('Z'); // false

Svar #7

kort sagt

function includes(k) {
  for(var i=0; i < this.length; i++){
    if( this[i] === k || ( this[i] !== this[i] && k !== k ) ){
      return true;
    }
  }
  return false;
}

Eksempel

function includes(k) {
  for(var i=0; i < this.length; i++){
    if( this[i] === k || ( this[i] !== this[i] && k !== k ) ){
      return true;
    }
  }
  return false;
}

function log(msg){
  $('#out').append('<div>' + msg + '</div>');  
}

var arr = [1, "2", NaN, true];
arr.includes = includes;

log('var arr = [1, "2", NaN, true];');
log('<br/>');
log('arr.includes(1): ' + arr.includes(1));
log('arr.includes(2): ' + arr.includes(2));
log('arr.includes("2"): ' + arr.includes("2"));
log('arr.includes(NaN): ' + arr.includes(NaN));
log('arr.includes(true): ' + arr.includes(true));
log('arr.includes(false): ' + arr.includes(false));
#out{
  font-family:monospace;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id=out></div>

Lengre svar

Jeg vet at dette spørsmålet egentlig ikke handler om hvorvidt man skal utvide innebygde objekter, men forsøket fra OP og kommentarene på dette svaret fremhever den debatten. Kommentaren min fra 12. feb. 2013 refererer til en artikkel som beskriver denne debatten veldig godt, men den lenken er ødelagt og jeg kan ikke redigere den opprinnelige kommentaren fordi det har gått for lang tid, så jeg inkluderer den her.

Hvis du ønsker å utvide det innebygde Array-objektet med en contains-metode, vil sannsynligvis den beste og mest ansvarlige måten å gjøre dette på være å bruke denne polyfillen fra MDN. (Se også denne delen av MDN-artikkelen om prototypisk arv, som forklarer at "Den eneste gode grunn for å utvide en innebygd prototype er å tilbakeføre funksjonene fra nyere JavaScript-motorer; for eksempel Array.forEach, osv.")

if (!Array.prototype.includes) {
  Array.prototype.includes = function(searchElement /*, fromIndex*/ ) {
    'use strict';
    var O = Object(this);
    var len = parseInt(O.length) || 0;
    if (len === 0) {
      return false;
    }
    var n = parseInt(arguments[1]) || 0;
    var k;
    if (n >= 0) {
      k = n;
    } else {
      k = len + n;
      if (k < 0) {k = 0;}
    }
    var currentElement;
    while (k < len) {
      currentElement = O[k];
      if (searchElement === currentElement ||
         (searchElement !== searchElement && currentElement !== currentElement)) {
        return true;
      }
      k++;
    }
    return false;
  };
}

Ikke vil ha streng likhet, eller vil du velge?

function includes(k, strict) {
  strict = strict !== false; // default is true
  // strict = !!strict; // default is false
  for(var i=0; i < this.length; i++){
    if( (this[i] === k && strict) || 
        (this[i] == k && !strict) ||
        (this[i] !== this[i] && k !== k)
    ) {
      return true;
    }
  }
  return false;
}

Svar #8

Mitt lille bidrag:

function isInArray(array, search)
{
    return array.indexOf(search) >= 0;
}

//usage
if(isInArray(my_array, "my_value"))
{
    //...
}

Svar #9

Hvis du har tilgang til ECMA 5, kan du bruke some-metoden.

MDN NOEN Metode Lenke

arrValues = ["Sam","Great", "Sample", "High"];

function namePresent(name){
  return name === this.toString();
}
// Note:
// namePresent requires .toString() method to coerce primitive value
// i.e. String {0: "S", 1: "a", 2: "m", length: 3, [[PrimitiveValue]]: "Sam"}
// into
// "Sam"

arrValues.some(namePresent, 'Sam');
=> true;

Hvis du har tilgang til ECMA 6, kan du bruke includes-metoden.

MDN INKLUDERER Metodekobling

arrValues = ["Sam","Great", "Sample", "High"];

arrValues.includes('Sam');
=> true;

Svar #10

Gitt implementeringen av indexOf for IE (som beskrevet av eyelidlessness):

Array.prototype.contains = function(obj) {
    return this.indexOf(obj) > -1;
};

Svar #11

Du kan bruke _.indexOf-metoden, eller hvis du ikke vil inkludere hele Underscore.js-biblioteket i appen din, kan du se på hvordan de gjorde det og trekke ut nødvendig kode.

    _.indexOf = function(array, item, isSorted) {
    if (array == null) return -1;
    var i = 0, l = array.length;
    if (isSorted) {
      if (typeof isSorted == 'number') {
        i = (isSorted < 0 ? Math.max(0, l + isSorted) : isSorted);
      } else {
        i = _.sortedIndex(array, item);
        return array[i] === item ? i : -1;
      }
    }
    if (nativeIndexOf && array.indexOf === nativeIndexOf) return array.indexOf(item, isSorted);
    for (; i < l; i++) if (array[i] === item) return i;
    return -1;
  };

Svar #12

Et annet alternativ ville være å bruke Array.some (hvis tilgjengelig) på følgende måte:

Array.prototype.contains = function(obj) {
  return this.some( function(e){ return e === obj } );
}

Den anonyme funksjonen som sendes til Array.some vil returnere true hvis og bare hvis det finnes et element i arrayen som er identisk med obj. I fravær av et slikt element vil funksjonen ikke returnere true for noen av elementene i arrayen, så Array.some vil også returnere false.

Relaterte artikler