Signatur
Beschreibung
Die Methode [Symbol.iterator]() von Array-Instanzen setzt das Iterable-Protokoll um. Überall, wo JavaScript ein Iterable erwartet, wird sie im Hintergrund aufgerufen. Das betrifft for...of-Schleifen, die Spread-Syntax ([...arr]), die Array-Destrukturierung, Array.from(), new Set(arr), new Map(arr), Promise.all() und yield*.
Diese Methode ist dieselbe Funktion wie Array.prototype.values(), es gilt also Array.prototype[Symbol.iterator] === Array.prototype.values. Zurück kommt ein neues Array-Iterator-Objekt. Dessen next()-Methode liefert Objekte der Form { value, done }, und zwar für jeden Index von 0 bis length - 1.
Direkt aufrufen muss man die Methode nur selten. Das lohnt sich, wenn du einen Iterator von Hand weiterschalten willst, etwa um das erste Element getrennt zu verarbeiten oder um Werte schrittweise zu verbrauchen. Außerdem kannst du die Methode überschreiben, um eigene Iterationslogik festzulegen. Das ist allerdings selten sinnvoll und kann eingebaute Funktionen beeinflussen.
Der Iterator ist live: Er prüft bei jedem Schritt die aktuelle length und liest den aktuellen Wert. Änderst du das Array während der Iteration, wirkt sich das auf die weiteren Werte aus.
Rückgabewert
undefined.Beispiele
Implizite Nutzung durch for...of und Spread
const farben = ['rot', 'grün', 'blau'];
// for...of ruft intern farben[Symbol.iterator]() auf
for (const farbe of farben) {
console.log(farbe);
}
// Spread und Destrukturierung ebenso
const kopie = [...farben];
const [erste, ...rest] = farben;
console.log(kopie, erste, rest);
Iterator manuell mit next() weiterschalten
const zahlen = [10, 20, 30];
const it = zahlen[Symbol.iterator]();
console.log(it.next()); // { value: 10, done: false }
console.log(it.next()); // { value: 20, done: false }
console.log(it.next()); // { value: 30, done: false }
console.log(it.next()); // { value: undefined, done: true }
Praxis: CSV-Kopfzeile getrennt verarbeiten
const zeilen = [
'name;alter',
'Anna;31',
'Ben;27'
];
const it = zeilen[Symbol.iterator]();
const kopf = it.next().value.split(';');
// Der Rest-Iterator ist selbst iterierbar
const datensaetze = [];
for (const zeile of it) {
const werte = zeile.split(';');
datensaetze.push(Object.fromEntries(kopf.map((k, i) => [k, werte[i]])));
}
console.log(datensaetze);
Generische Funktion: prüfen, ob ein Wert iterierbar ist
const istIterierbar = (wert) =>
wert != null && typeof wert[Symbol.iterator] === 'function';
console.log(istIterierbar([1, 2])); // true
console.log(istIterierbar('abc')); // true
console.log(istIterierbar({ a: 1 })); // false
console.log(Array.prototype[Symbol.iterator] === Array.prototype.values);
// Wichtig · Fallstricke
- Identisch mit
values():Array.prototype[Symbol.iterator]undArray.prototype.valuessind dasselbe Funktionsobjekt. - Einmal verbrauchbar: Ein Iterator lässt sich nur einmal durchlaufen. Wenn du ein zweites Mal iterieren willst, musst du
arr[Symbol.iterator]()erneut aufrufen. Das Array selbst kannst du dagegen beliebig oft iterieren. - Live-Verhalten: Elemente, die während der Iteration angehängt werden, liefert der Iterator mit. Beim Entfernen werden Elemente übersprungen. Deshalb das Array beim Iterieren nicht verändern.
- Löcher: Anders als
forEach()überspringt der Iterator leere Plätze nicht, sondern liefert dortundefined. - Überschreiben ist riskant: Überschreibst du
Array.prototype[Symbol.iterator], ändert sich das Verhalten von Spread, Destrukturierung,Array.from()usw. im ganzen Programm. Außerdem kann das Optimierungen der Engine ausschalten. - Generisch: Die Methode funktioniert auch mit array-ähnlichen Objekten, z. B.
Array.prototype[Symbol.iterator].call({ length: 2, 0: 'a', 1: 'b' }). - Kompatibilität: Wird seit ES2015 von allen modernen Browsern und von Node.js unterstützt. Der Internet Explorer unterstützt die Methode nicht, dort sind Polyfills nötig (z. B. core-js).