JavaScript/Objekte/Array/includes

Aus SELFHTML-Wiki
Wechseln zu: Navigation, Suche

Die von Array.prototype vererbte Methode includes prüft, ob in dem Array auf dem sie aufgerufen wurde ein bestimmter Wert enthalten ist und gibt als Ergebnis einen booleschen Wert zurück. Bei includes handelt es sich um eine generische Methode, sie kann also auch im Kontext von Objekten aufgerufen werden, die keine Arrays sind.


Syntax

Array.prototype.includes(searchElement[, fromIndex])


Attribute
Writable true
Enumerable false
Configurable true


Prototyp


Eigenschaften


Beschreibung

Die Methode erwartet als ersten Parameter den Wert, nach dem das Array durchsucht werden soll. Der optionale zweite Parameter bestimmt den Startindex für die Suche. Wird der gesuchte Wert in dem Array gefunden, dann wird der boolesche Wert true zurückgegeben, sonst der Wert false. Ist der gesuchte Wert in dem Array mehrfach vorhanden, wird die Suche bei der ersten Übereinstimmung beendet.


Beispiel
const array = [16, 32, 64, 128];

console.log(array.includes(64)); // true


Wenn wie in dem Beispiel oben kein Argument für den optionalen zweiten Parameter übergeben wird, dann wird als Standardwert für den Startindex Null verwendet. Das heißt, in diesem Fall wird das ganze Array nach dem Wert durchsucht, der als erstes Argument übergeben wurde.


Beispiel
const planets = ['Neptune', 'Jupiter', 'Saturn'];

console.log(planets.includes( )); // false

delete planets[1];

console.log(planets.includes( )); // true


Wird die Methode includes ohne Argumente aufgerufen, dann wird der erste Parameter standardmäßig mit dem Wert undefined initialisiert und entsprechend geprüft, ob in dem Array ein Element mit diesem Wert existiert. Dies ist bei der ersten Prüfung in dem Beispiel oben nicht der Fall, weshalb hier false der Rückgabewert ist. Wird allerdings ein Element des Arrays mit dem Operator delete gelöscht, dann rücken die nachfolgenden Elemente nicht auf um die Lücke zu schließen, sondern es wird lediglich der Wert des gelöschten Elementes auf undefined gesetzt. In diesem Fall ergibt die Prüfung also true.


Beispiel
const stars = ['Arcturus', 'Spica', 'Orionis'];

stars.splice(1, 1);

console.log(stars); // [Arcturus, Orionis]

console.log(stars.includes(undefined)); // false


Es ist allerdings ohnehin nicht empfehlenswert, Elemente eines Arrays mit dem Operator zu Löschung von Objekteigenschaften zu entfernen. Hierzu sollte immer die Methode splice verwendet werden, denn gegebenenfalls entstehende Lücken im Index werden bei Verwendung dieser Methode geschlossen. Sie ermöglicht es darüber hinaus auch, mehr als ein Element zu entfernen oder ein oder mehrere Elemente des Arrays zu ersetzten.


Beispiel
const array = [2, 4, 8, NaN];

console.log(array.some(item => item === NaN)); // false

console.log(array.includes(NaN)); // true


Beim Gebrauch der Methode includes ist weiter zu berücksichtigen, dass bei dem Vergleich der Werte des Arrays mit dem gesuchten Wert der Algorithmus Same Value Zero verwendet wird, das heißt, anders als bei der Prüfung auf Strict Equality wird hier auch dann der Wert true zurückgegeben, wenn der gesuchte Wert NaN ist. Da selbst die Prüfung auf strenge Gleichheit bei NaN false ergibt, muss normalerweise unter Verwendung der eingebauten Methode isNaN geprüft werden, ob es sich bei einem Wert um NaN handelt.


Beispiel
const planets = ['Mercury', 'Venus', 'Earth', 'Mars'];

console.log(planets.includes('Venus', 2)); // false

console.log(planets.includes('Earth', 2)); // true


Durch Übergabe eines Arguments für den optionalen zweiten Parameter der Methode includes kann der Index bestimmt werden, an dem die Suche beginnen soll. Wird also wie in dem Beispiel oben beim Aufruf der Wert 2 übergeben, dann ist das Element an der Indexposition 2 das erste Element, das mit dem gesuchten Wert verglichen wird. Das Ende der Suche markiert grundsätzlich das Element mit dem höchsten Index, also der letzte Eintrag in dem Array.


Beispiel
const numbers = [2, 3, 5, 7];

console.log(numbers.length); // 4

console.log(numbers.includes(5, 4)); // false


Ist der als zweites Argument übergebene Wert größer als die von der Eigenschaft length repräsentierte Anzahl der in dem Array enthaltenen Elemente, dann wird von der Methode includes grundsätzlich der boolesche Wert false zurückgegeben. Das Array wird also nur dann durchsucht, wenn der Startindex mindestens um Eins kleiner ist als die Länge des Arrays.

Relativer Wert für den Startindex

Wird der Methode includes als zweites Argument ein numerischer Wert übergeben, der kleiner ist als Null, dann wird die Länge des Arrays zu diesem Wert addiert und das Ergebnis als Startwert verwendet, sofern dieses größer oder gleich Null ist. Sonst wird die Suche standardmäßig an der ersten Indexposition des Arrays begonnen.


Beispiel
const satellites = ['Ganymede', 'Callisto', 'Thebe'];

console.log(satellites.includes('Ganymede', -2)); // false

console.log(satellites.includes('Thebe', -2)); // true


In dem Beispiel oben wird als zweites Argument jeweils der negative Wert -2 übergeben. Zu diesem Wert wird nun die Anzahl der in dem Array enthaltenen Elemente hinzugezählt, also 3, was im Ergebnis den Wert 1 ergibt. Die Suche wird hier demnach bei dem Element begonnen, das den Index 1 hat. Entsprechend ergibt die erste Suche mittels includes den Wert false, da der gesuchte Wert in dem Array nur bei dem Element mit dem Index 0 vorkommt.


Beispiel
const array = [true, false, null];

console.log(array.includes(true, -5)); // true


Wird für den Startindex ein Wert angegeben, der selbst nach der Addtion mit dem Wert der Eigenschaft length immer noch kleiner ist als 0, dann wird dieser ignoriert und die Suche bei dem Element mit dem Index 0 begonnen. In diesem Fall wird also grundsätzlich das ganze Array durchsucht.

Typumwandlungen

Auf den Wert des zweiten Parameters der Methode includes wird grundsätzlich die abstrakte Operation ToInteger angewendet, nach deren Regeln zum Beispiel der Wert NaN durch 0 ersetzt wird.


Beispiel
console.log([1, 2, 3].includes(2, NaN)); // true

console.log([4, 5, 6].includes(5, Infinity)); // false

console.log([7, 8, 9].includes(8, -Infinity)); // true


Wird als zweites Argument der Wert Infinity übergeben, dann werden auf diesen die allgemeinen, oben beschriebenen Regeln angewendet, also je nach Vorzeichen entweder der Startindex 0 verwendet, oder der Wert der Eigenschaft length des Arrays. Entsprechend wird bei negativer Unendlichkeit das ganze Array durchsucht und bei positiver Unendlichkeit passiert nichts.


Beispiel
const array = ['Charon', 'Hydra', 'Styx'];

console.log(array.includes('Charon', -2.8)); // false


Handelt es sich bei dem für den Startindex übergebenen Wert um eine gebrochene Zahl, dann wird nach den Regeln der Operation ToInteger das Ergebnis der auf dem Absolutbetrag des Wertes ausgeführten Abrundungsfunktion zurückgegeben.


Hinweis:
Der absolute Betrag (abs) einer Zahl ist definiert als der Abstand zu Null, weshalb beispielsweise -5 und 5 jeweils den Absolutbetrag 5 ergeben. Es ist in diesem Zusammenhang also zu beachten, dass die Abrundungsfunktion (floor) hier immer auf dem absoluten Betrag des übergebenen Wertes durchgeführt wird und nicht auf dem Wert selbst, denn dies würde bei einer negativen Zahl natürlich ein anderes Ergebnis bringen.


In dem Beispiel oben wird von includes also schließlich der Wert false zurückgegeben, denn der für den Startindex übergebene negative Wert besitzt den Absolutbetrag 2.8, was abgerundet 2 ergibt. Weil beim Rückgabewert der Operation ToInteger das Vorzeichen allerdings nicht geändert wird, ist das Ergebnis hier immer noch negativ, weshalb die Länge des Arrays hinzugezählt wird. Der verwendete Index für den Start der Suche ist in diesem Fall also 1, wohingegen der gesuchte Wert nur bei dem Element mit dem Index 0 zu finden gewesen wäre.


Beispiel
console.log([4, 8, 16, 32].includes(4, true)); // false

console.log(['alpha', 'beta'].includes('alpha', false)); // true

console.log([64, 128, 256].includes(64, null)); // true


Wird der Methode ein Wert für den Startindex gegeben der nicht vom Datentyp Number ist, dann wird keine Ausnahme geworfen sondern wie üblich versucht, diesen Wert in eine Zahl zu konvertieren, was nach den Regeln der abstrakten Operation ToNumber zum Beispiel für den booleschen Wert true die Zahl 1 ergibt und für false die Zahl 0, ebenso wie es bei dem primitiven Wert null der Fall ist.

Generische Verwendung

Die Verwendung der Methode includes ist nicht auf Arrays beschränkt, sondern sie kann auch im Kontext von anderen Objekten aufgerufen werden. Dies kann beispielsweise mit der Methode call bewerkstelligt werden, welche von Function.prototype an die Methode includes vererbt wird. Die Methode call erwartet als erstes Argument das Objekt, in dessen Kontext die jeweilige Funktion aufgerufen werden soll und alle weiteren an call übergebenen Argumente werden an diese Funktion weitergereicht.


Beispiel
function test ( ) {
  return Array.prototype.includes.call(arguments, 16, 1);
}

console.log(test(8, 16, 32)); // true


Auf diese Weise kann also zum Beispiel das exotische Objekt arguments mittels includes durchsucht werden, welches die an eine Funktion überebenen Argumente beinhaltet und bei dem es sich nicht um ein Array handelt. Statt die Methode includes direkt auf Array.prototype anzusprechen wie in dem Beispiel oben, könnte zu diesem Zweck aber natürlich auch ein leeres Arrayliteral verwendet werden.

Eigene Eigenschaften

Die Methode includes besitzt zwei eigene Eigenschaften, nämlich name und length. Der Wert der Eigenschaft name ist die Zeichenkette includes, also der Name der Methode und die Werte der internen Attribute dieser Eigenschaft sind false für Writable, false für Enumerable und true für Configurable. Die Eigenschaft ist also standardmäßig schreibgeschützt, kann aber unter Verwendung von Methoden wie zum Beispiel defineProperty von Object verändert werden.


Beispiel
const includes = Array.prototype.includes;

console.log(Object.getOwnPropertyNames(includes)); // [length, name]

console.log(includes.name); // includes


Die Eigenschaft length der Methode includes hat den Wert 1, da die Funktion nur über einen formalen Parameter verfügt, welcher den Wert erwartet, nach dem das Array durchsucht werden soll. Optionale Parameter werden bei der Berechnung der Länge einer Funktion ebenso wie Restparameter grundsätzlich nicht berücksichtigt.


Beispiel
const length = [ ].includes.length;

console.log(length); // 1


Die Werte der internen Attribute der Eigenschaft length sind dieselben wie bei der Eigenschaft name, also false für Writable, false für Enumerable und true für Configurable. Auch bei dieser Eigenschaft kann der Wert also nicht durch einfache Zuweisung (Assignment), sondern nur durch Definition verändert werden.

Beispiel für Polyfill

Da die Methode includes erst seit ECMAScript 2016 offiziell standardisiert ist und sie zum Zeitpunkt der Erstellung dieses Artikels noch nicht von allen wichtigen Ausführungsumgebungen unterstützt wird, sei im Folgenden ein Beispiel für ein Polyfill gegeben. Dabei wird zunächst geprüft, ob eine Methode mit dem Namen includes auf Array.prototype definiert ist. Wenn das nicht der Fall ist, wird eine entsprechende Methode angelegt.


Beispiel
if (!Array.prototype.includes) {
 
  Array.prototype.includes = function includes (searchElement) {
    if (this == null) {
      throw new TypeError('this is null or undefined');
    }

    var object = Object(this),
        length = object.length >>> 0;

    if (length === 0) {
      return false;
    }

    var start = arguments[1] >> 0,
        key = start < 0 ? Math.max(start + length, 0) : start,
        currentElement;

    while (key < length) {
      currentElement = object[key];

      if (searchElement === currentElement
      || (searchElement !== searchElement
      && currentElement !== currentElement)) {
        return true
      }

      key ++;
    }

    return false;
  };
 
}


Der Stand der Unterstützung der Methode bei einer großen Auswahl an Ausführungsumgebungen kann darüber hinaus durch einen Blick auf die Tabelle zur Kompatibilität von Kangax in Erfahrung gebracht werden.


Hinweis:
Normalerweise ist es schlechte Praxis, an eingebauten Objekten Veränderungen vorzunehmen, da sich alle gegenwärtig oder zukünftig eingebundenen Programme innerhalb einer globalen Umgebung dieselben Objekte teilen. Die Manipulation dieser Objekte kann also zu Konflikten zwischen Programmen und mithin zu Fehlern führen. Die Bereitstellung von Polyfills für eventuell von der Ausführungsumgebung nicht unterstützte, standardkonforme Methoden wie in diesem Beispiel bildet jedoch eine Ausnahme von dieser Regel, denn die Verwendung von Sprachmitteln sollte grundsätzlich nicht davon abhängig gemacht werden, ob diese wirklich von allen Ausführungsumgebungen unterstützt werden, sondern allein davon, ob deren Verwendung für die Bewältigung der jeweiligen programmiertechnische Aufgabe die beste Wahl darstellt.

Weblinks

  • ECMAScript 2017 (7th Edition, ECMA-262 Draft): ToInteger