Signatur
Beschreibung
Die Methode [Symbol.iterator]() auf Iterator.prototype implementiert das Iterable-Protokoll für alle eingebauten Iteratoren. Ihre Implementierung ist trivial: Sie gibt einfach this zurück. Dadurch ist jeder Iterator (z. B. von Array.prototype.values(), Map.prototype.entries(), String.prototype[Symbol.iterator]() oder Generator-Objekten) gleichzeitig ein Iterable.
Das ist der Grund, warum man Iteratoren direkt an Syntax übergeben kann, die ein Iterable erwartet: for...of, den Spread-Operator ..., Destrukturierung, yield*, Array.from(), new Map(), new Set(), Promise.all() usw. Diese Konstrukte rufen intern zuerst [Symbol.iterator]() auf und erhalten so den Iterator selbst zurück.
Eigene Iterator-Klassen, die von Iterator erben (class MyIter extends Iterator) oder deren Prototyp-Kette Iterator.prototype enthält, bekommen dieses Verhalten automatisch geschenkt. Wichtig: Weil derselbe Iterator zurückgegeben wird, ist ein Iterator nur einmal durchlaufbar – nach dem ersten vollständigen Durchlauf ist er erschöpft.
Rückgabewert
this – also das Iterator-Objekt selbst, keine Kopie und kein neuer Iterator.Beispiele
Iterator gibt sich selbst zurück
const iter = [10, 20, 30].values();
console.log(iter[Symbol.iterator]() === iter);
// Deshalb funktioniert for...of direkt auf dem Iterator
for (const n of iter) {
console.log(n);
}
Iterator ist nur einmal konsumierbar
const entries = new Map([['a', 1], ['b', 2]]).entries();
const first = [...entries];
const second = [...entries]; // gleicher, bereits erschöpfter Iterator
console.log(first);
console.log(second);
Teilweise konsumieren und Rest weiterverarbeiten
// CSV-Zeilen: erste Zeile ist Kopfzeile
const lines = 'name,alter\nAnna,31\nBen,27'.split('\n')[Symbol.iterator]();
const header = lines.next().value.split(',');
// Rest direkt per for...of – möglich dank [Symbol.iterator]() === this
const rows = [];
for (const line of lines) {
const values = line.split(',');
rows.push(Object.fromEntries(header.map((h, i) => [h, values[i]])));
}
console.log(rows);
Eigener Iterator erbt das Verhalten von Iterator
class Countdown extends Iterator {
#n;
constructor(start) {
super();
this.#n = start;
}
next() {
return this.#n > 0
? { value: this.#n--, done: false }
: { value: undefined, done: true };
}
}
const cd = new Countdown(3);
console.log([...cd]); // [Symbol.iterator] kommt von Iterator.prototype
// Wichtig · Fallstricke
- Einmal-Durchlauf: Da
thiszurückgegeben wird, liefert ein zweitesfor...ofoder Spread auf demselben Iterator keine Werte mehr. Wer mehrfach iterieren will, sollte das zugrunde liegende Iterable (Array, Map, Set) verwenden oder die Werte mitArray.from()puffern. - Vorzeitiger Abbruch: Ein
breakinfor...ofruftreturn()auf dem Iterator auf (falls vorhanden) – Generatoren werden dadurch beendet und lassen sich danach nicht fortsetzen. - Eigene Iteratoren: Handgeschriebene Iterator-Objekte (nur mit
next()) sind nicht automatisch iterierbar. Entweder vonIteratorerben,Iterator.from()verwenden oder selbst[Symbol.iterator]() { return this; }ergänzen. - Kompatibilität: Die Methode existiert auf dem (früher verborgenen)
%IteratorPrototype%seit ES2015 in allen Browsern. Das globaleIterator-Objekt samtextends Iteratorund Iterator-Helpern ist erst mit ES2025 standardisiert (Chrome 122+, Firefox 131+, Safari 18.4+, Node.js 22+).