Start · Sprachen · JavaScript · Referenz · Array

Array

Klasse

Geordnete Liste beliebiger Werte mit zahlreichen eingebauten Methoden zum Suchen, Transformieren und Verwalten von Elementen.

seit JavaScript ES1 Kategorie: core

Signatur

class Array

Beschreibung

In JavaScript sind Arrays keine Primitives, sondern Array-Objekte mit den folgenden Kerneigenschaften:

  • JavaScript-Arrays sind in ihrer Größe veränderbar und können eine Mischung verschiedener Datentypen enthalten. (Wenn diese Eigenschaften unerwünscht sind, verwende stattdessen typed arrays.)
  • JavaScript-Arrays sind keine assoziativen Arrays, daher können Array-Elemente nicht über beliebige Strings als Indizes angesprochen werden, sondern müssen über nicht-negative Ganzzahlen (oder deren jeweilige String-Form) als Indizes angesprochen werden.
  • JavaScript-Arrays sind nullbasiert indiziert: das erste Element eines Arrays hat den Index 0, das zweite den Index 1 und so weiter — und das letzte Element hat den Wert der length-Eigenschaft des Arrays minus 1.
  • JavaScript-Array-Kopieroperationen erzeugen shallow copies. (Alle standardmäßigen eingebauten Kopieroperationen mit beliebigen JavaScript-Objekten erzeugen shallow copies, keine deep copies.)

Array-Indizes

Array-Objekte können keine beliebigen Strings als Element-Indizes verwenden (wie in einem assoziativen Array), sondern müssen nicht-negative Ganzzahlen (oder deren jeweilige String-Form) verwenden. Das Setzen oder Zugreifen über Nicht-Ganzzahlen setzt oder liest kein Element aus der Array-Liste selbst, sondern setzt oder liest eine Variable, die zur Objekt-Property-Sammlung des Arrays gehört. Die Objekt-Properties des Arrays und die Liste der Array-Elemente sind getrennt, und die Traversierungs- und Mutationsoperationen des Arrays können nicht auf diese benannten Properties angewendet werden.

Array-Elemente sind Objekt-Properties auf die gleiche Weise wie toString eine Property ist (um genau zu sein, ist toString() jedoch eine Methode). Dennoch führt der Versuch, wie folgt auf ein Element eines Arrays zuzugreifen, zu einem SyntaxError, weil der Property-Name ungültig ist:

Die JavaScript-Syntax erfordert, dass Properties, die mit einer Ziffer beginnen, über Bracket-Notation statt Dot-Notation angesprochen werden. Es ist auch möglich, die Array-Indizes in Anführungszeichen zu setzen (z. B. years['2'] statt years[2]), obwohl das meist nicht nötig ist.

Die 2 in years[2] wird von der JavaScript-Engine durch eine implizite toString-Umwandlung in einen String konvertiert. Als Ergebnis würden '2' und '02' auf zwei verschiedene Slots des years-Objekts verweisen, und das folgende Beispiel könnte true sein:

Nur years['2'] ist ein tatsächlicher Array-Index. years['02'] ist eine beliebige String-Property, die bei der Array-Iteration nicht besucht wird.

Beziehung zwischen length und numerischen Properties

Die length-Eigenschaft eines JavaScript-Arrays und die numerischen Properties sind miteinander verbunden.

Mehrere der eingebauten Array-Methoden (z. B. join(), slice(), indexOf() usw.) berücksichtigen den Wert der length-Eigenschaft eines Arrays, wenn sie aufgerufen werden.

Andere Methoden (z. B. push(), splice() usw.) führen ebenfalls zu Aktualisierungen der length-Eigenschaft eines Arrays.

Wenn eine Property auf einem JavaScript-Array gesetzt wird und diese Property ein gültiger Array-Index ist und dieser Index außerhalb der aktuellen Grenzen des Arrays liegt, aktualisiert die Engine die length-Eigenschaft des Arrays entsprechend:

Das Erhöhen der length erweitert das Array, indem leere Slots hinzugefügt werden, ohne neue Elemente zu erzeugen — nicht einmal undefined.

Das Verringern der length-Eigenschaft löscht jedoch Elemente.

Array-Methoden und leere Slots

Array-Methoden verhalten sich unterschiedlich, wenn sie auf leere Slots in sparse arrays treffen. Im Allgemeinen behandeln ältere Methoden (z. B. forEach) leere Slots anders als Indizes, die undefined enthalten.

Zu den Methoden mit spezieller Behandlung leerer Slots gehören: concat(), copyWithin(), every(), filter(), flat(), flatMap(), forEach(), indexOf(), lastIndexOf(), map(), reduce(), reduceRight(), reverse(), slice(), some(), sort() und splice(). Iterationsmethoden wie forEach besuchen leere Slots überhaupt nicht. Andere Methoden wie concat, copyWithin usw. bewahren leere Slots beim Kopieren, sodass das Array am Ende immer noch sparse ist.

Neuere Methoden (z. B. keys) behandeln leere Slots nicht besonders und behandeln sie so, als enthielten sie undefined. Methoden, die leere Slots mit undefined-Elementen gleichsetzen, sind: entries(), fill(), find(), findIndex(), findLast(), findLastIndex(), includes(), join(), keys(), toLocaleString(), toReversed(), toSorted(), toSpliced(), values() und with().

Kopierende Methoden und mutierende Methoden

Manche Methoden mutieren das existierende Array, auf dem die Methode aufgerufen wurde, nicht, sondern geben ein neues Array zurück. Sie tun dies, indem sie zunächst ein neues Array konstruieren und es dann mit Elementen füllen. Das Kopieren erfolgt immer shallow — die Methode kopiert niemals etwas über das ursprünglich erstellte Array hinaus. Elemente des/der ursprünglichen Array(s) werden wie folgt in das neue Array kopiert:

  • Objekte: die Objektreferenz wird in das neue Array kopiert. Sowohl das ursprüngliche als auch das neue Array verweisen auf dasselbe Objekt. Das heißt, wenn ein referenziertes Objekt geändert wird, sind die Änderungen sowohl im neuen als auch im ursprünglichen Array sichtbar.
  • Primitive Typen wie Strings, Numbers und Booleans (nicht String-, Number- und Boolean-Objekte): ihre Werte werden in das neue Array kopiert.

Andere Methoden mutieren das Array, auf dem die Methode aufgerufen wurde, wobei ihr Rückgabewert je nach Methode unterschiedlich ist: manchmal eine Referenz auf dasselbe Array, manchmal die Länge des neuen Arrays.

Die folgenden Methoden erzeugen neue Arrays durch Zugriff auf this.constructor[Symbol.species], um den zu verwendenden Konstruktor zu bestimmen: concat(), filter(), flat(), flatMap(), map(), slice() und splice() (zur Konstruktion des Arrays der entfernten Elemente, das zurückgegeben wird).

Die folgenden Methoden erzeugen immer neue Arrays mit dem Array-Basiskonstruktor: toReversed(), toSorted(), toSpliced() und with().

Ein einfacher Weg, eine mutierende Methode in eine nicht-mutierende Alternative zu verwandeln, ist die Verwendung der spread syntax oder slice(), um zunächst eine Kopie zu erstellen.

Iterative Methoden

Viele Array-Methoden nehmen eine callback-Funktion als Argument. Die callback-Funktion wird sequenziell und höchstens einmal für jedes Element im Array aufgerufen, und der Rückgabewert der callback-Funktion wird verwendet, um den Rückgabewert der Methode zu bestimmen. Alle haben dieselbe Signatur:

Dabei nimmt callbackFn drei Argumente:

  • element: Das aktuelle Element, das im Array verarbeitet wird.
  • index: Der Index des aktuellen Elements, das im Array verarbeitet wird.
  • array: Das Array, auf dem die Methode aufgerufen wurde.

Was callbackFn zurückgeben soll, hängt von der aufgerufenen Array-Methode ab.

Das Argument thisArg (Standard: undefined) wird beim Aufruf von callbackFn als this-Wert verwendet. Der letztlich von callbackFn beobachtbare this-Wert wird nach den üblichen Regeln bestimmt: wenn callbackFn non-strict ist, werden primitive this-Werte in Objekte verpackt, und undefined/null wird durch globalThis ersetzt. Das Argument thisArg ist irrelevant für jede callbackFn, die mit einer arrow function definiert wurde, da arrow functions kein eigenes this-binding haben.

Das an callbackFn übergebene array-Argument ist am nützlichsten, wenn du während der Iteration einen anderen Index lesen möchtest, weil du möglicherweise nicht immer eine bestehende Variable hast, die auf das aktuelle Array verweist. Du solltest das Array während der Iteration im Allgemeinen nicht mutieren (siehe mutating initial array in iterative methods), aber du kannst dieses Argument auch dazu verwenden. Das array-Argument ist nicht das Array, das gebaut wird, im Falle von Methoden wie map(), filter() und flatMap() — es gibt keine Möglichkeit, aus der callback-Funktion auf das gerade gebaute Array zuzugreifen.

Alle iterativen Methoden sind kopierend und generisch, obwohl sie sich bei leeren Slots unterschiedlich verhalten.

Die folgenden Methoden sind iterativ: every(), filter(), find(), findIndex(), findLast(), findLastIndex(), flatMap(), forEach(), map() und some().

Insbesondere rufen every(), find(), findIndex(), findLast(), findLastIndex() und some() callbackFn nicht immer für jedes Element auf — sie stoppen die Iteration, sobald der Rückgabewert festgelegt ist.

Die Methoden reduce() und reduceRight() nehmen ebenfalls eine callback-Funktion und rufen sie höchstens einmal für jedes Element im Array auf, haben aber leicht abweichende Signaturen von typischen iterativen Methoden (sie akzeptieren beispielsweise kein thisArg).

Die sort()-Methode nimmt ebenfalls eine callback-Funktion, ist aber keine iterative Methode. Sie mutiert das Array in-place, akzeptiert kein thisArg und kann den callback mehrfach für einen Index aufrufen.

Generische Array-Methoden

Array-Methoden sind immer generisch — sie greifen nicht auf interne Daten des Array-Objekts zu. Sie greifen nur über die length-Eigenschaft und die indizierten Elemente auf die Array-Elemente zu. Das bedeutet, dass sie auch auf array-like Objekten aufgerufen werden können.

Normalisierung der length-Eigenschaft

Die length-Eigenschaft wird in eine Ganzzahl konvertiert und dann auf den Bereich zwischen 0 und 253 - 1 begrenzt. NaN wird zu 0, sodass sich length auch dann so verhält, als hätte es den Wert 0, wenn es nicht vorhanden oder undefined ist.

Die Sprache vermeidet es, length auf einen unsicheren Integer zu setzen. Alle eingebauten Methoden werfen einen TypeError, wenn length auf eine Zahl größer als 253 - 1 gesetzt werden soll. Da die length-Eigenschaft von Arrays jedoch einen Fehler wirft, wenn sie auf mehr als 232 - 1 gesetzt wird, wird die Grenze der sicheren Integer normalerweise nur erreicht, wenn die Methode auf einem Nicht-Array-Objekt aufgerufen wird.

Einige Array-Methoden setzen die length-Eigenschaft des Array-Objekts. Sie setzen den Wert stets nach der Normalisierung, sodass length immer als Ganzzahl endet.

Array-like Objekte

Der Begriff array-like object bezieht sich auf jedes Objekt, das während des oben beschriebenen length-Konvertierungsprozesses keinen Fehler wirft. In der Praxis wird erwartet, dass ein solches Objekt tatsächlich eine length-Eigenschaft hat und indizierte Elemente im Bereich 0 bis length - 1 besitzt. (Wenn es nicht alle Indizes hat, ist es funktional äquivalent zu einem sparse array.) Jeder ganzzahlige Index kleiner als null oder größer als length - 1 wird ignoriert, wenn eine Array-Methode auf einem array-like-Objekt operiert.

Viele DOM-Objekte sind array-like — zum Beispiel NodeList und HTMLCollection. Auch das arguments-Objekt ist array-like. Du kannst Array-Methoden auf ihnen aufrufen, auch wenn sie diese Methoden selbst nicht haben.

Rückgabewert

Typ
Array
Beschreibung
Beim Aufruf von new Array() oder über ein Array-Literal entsteht eine neue Array-Instanz.

Beispiele

Grundlegende Array-Erstellung und häufige Operationen

// Array-Literal
const fruits = ['Apfel', 'Banane', 'Kirsche'];

// Lesen per Index
console.log(fruits[0]); // 'Apfel'

// Elemente hinzufügen / entfernen
fruits.push('Mango');     // Ende anfügen
fruits.pop();             // letztes Element entfernen
fruits.unshift('Ananas'); // Anfang einfügen
fruits.shift();           // erstes Element entfernen

console.log(fruits.length); // 3
console.log(fruits);        // ['Apfel', 'Banane', 'Kirsche']
3 ['Apfel', 'Banane', 'Kirsche']

Transformation und funktionale Methoden

const zahlen = [1, 2, 3, 4, 5];

// Alle Werte verdoppeln
const doppelt = zahlen.map(n => n * 2);
console.log(doppelt); // [2, 4, 6, 8, 10]

// Nur gerade Zahlen
const gerade = zahlen.filter(n => n % 2 === 0);
console.log(gerade); // [2, 4]

// Summe berechnen
const summe = zahlen.reduce((acc, n) => acc + n, 0);
console.log(summe); // 15

// Suchen
console.log(zahlen.find(n => n > 3));    // 4
console.log(zahlen.includes(3));          // true

// Verschachtelte Arrays glätten
const nested = [[1, 2], [3, [4, 5]]];
console.log(nested.flat(2)); // [1, 2, 3, 4, 5]
[2, 4, 6, 8, 10] [2, 4] 15 4 true [1, 2, 3, 4, 5]

Moderne, nicht-mutierende Methoden (ES2023)

const original = [3, 1, 4, 1, 5];

// Kopie sortiert zurückgeben – original bleibt unverändert
const sortiert = original.toSorted((a, b) => a - b);
console.log(sortiert);  // [1, 1, 3, 4, 5]
console.log(original);  // [3, 1, 4, 1, 5]

// Einzelnes Element ersetzen ohne Mutation
const geaendert = original.with(2, 99);
console.log(geaendert); // [3, 1, 99, 1, 5]

// Umkehren ohne Mutation
const umgekehrt = original.toReversed();
console.log(umgekehrt); // [5, 1, 4, 1, 3]
[1, 1, 3, 4, 5] [3, 1, 4, 1, 5] [3, 1, 99, 1, 5] [5, 1, 4, 1, 3]

Array.from() und Array.of()

// Aus einem iterierbaren Objekt (z. B. Set oder NodeList)
const einzigartig = Array.from(new Set([1, 2, 2, 3, 3, 4]));
console.log(einzigartig); // [1, 2, 3, 4]

// Mit Mapping-Funktion: Zahlen 0–4 quadrieren
const quadrate = Array.from({ length: 5 }, (_, i) => i ** 2);
console.log(quadrate); // [0, 1, 4, 9, 16]

// Array.of() – verhindert Sonderverhalten von new Array(n)
const einzeln = Array.of(7);
console.log(einzeln);        // [7]  (kein leeres Array der Länge 7!)
console.log(new Array(7));   // [ <7 empty items> ]
[1, 2, 3, 4] [0, 1, 4, 9, 16] [7] [ <7 empty items> ]

// Wichtig · Fallstricke

Sparse Arrays vermeiden: Wird new Array(5) ohne Initialwerte verwendet oder werden Indizes übersprungen (arr[100] = 1), entstehen Lücken. Methoden wie map und filter überspringen diese Lücken, während forEach sie ebenfalls ignoriert – das Verhalten ist inkonsistent und fehleranfällig.

Mutierend vs. nicht-mutierend: Klassische Methoden wie sort(), reverse(), splice() verändern das ursprüngliche Array. Die ab ES2023 eingeführten Gegenstücke toSorted(), toReversed() und toSpliced() geben stattdessen eine neue Kopie zurück und sind für funktionalen Code vorzuziehen.

Performance: Für große Mengen numerischer Daten sind TypedArray-Varianten (Float64Array, Int32Array etc.) deutlich performanter, da sie zusammenhängenden, typreinen Speicher nutzen.

Browser-Kompatibilität: Die Kernfunktionalität ist in allen Browsern verfügbar. Neuere Methoden wie toSorted, toReversed, with und findLast erfordern aktuelle Browser-Versionen (Baseline 2023). Array.from() und Array.of() sind seit ES2015 verfügbar.