| [ Web Proxy ] |
| Viewing: https://developer.mozilla.org/de/docs/Web/JavaScript/Guide/Iterators_and_generators | [Back] [Original] |
Get to know MDN better
Dieser Inhalt wurde automatisch aus dem Englischen bersetzt, und kann Fehler enthalten. Erfahre mehr ber dieses Experiment.
Iteratoren und Generatoren bringen das Konzept der Iteration direkt in die Kernsprache und bieten einen Mechanismus zur Anpassung des Verhaltens von for...of-Schleifen.
Fr weitere Details siehe auch:
In JavaScript ist ein Iterator ein Objekt, das eine Sequenz definiert und mglicherweise einen Rckgabewert bei dessen Beendigung.
Speziell ist ein Iterator jedes Objekt, das das Iterator-Protokoll implementiert, indem es eine next()-Methode besitzt, die ein Objekt mit zwei Eigenschaften zurckgibt:
valueDer nchste Wert in der Iterationssequenz.
doneDies ist true, wenn der letzte Wert in der Sequenz bereits verbraucht wurde. Wenn value zusammen mit done vorhanden ist, ist es der Rckgabewert des Iterators.
Sobald ein Iterator-Objekt erstellt wurde, kann es explizit iteriert werden, indem wiederholt next() aufgerufen wird. Das Iterieren ber einen Iterator wird als Verbrauch des Iterators bezeichnet, da es im Allgemeinen nur einmal mglich ist. Nachdem ein Endwert geliefert wurde, sollten zustzliche Aufrufe von next() weiterhin {done: true} zurckgeben.
Der hufigste Iterator in JavaScript ist der Array-Iterator, der jeden Wert im zugehrigen Array in Reihenfolge zurckgibt.
Obwohl es leicht vorstellbar ist, dass alle Iteratoren als Arrays ausgedrckt werden knnten, ist dies nicht wahr. Arrays mssen vollstndig zugewiesen werden, aber Iteratoren werden nur bei Bedarf verbraucht. Aufgrund dessen knnen Iteratoren Sequenzen unbegrenzter Gre ausdrcken, wie etwa den Zahlenbereich zwischen 0 und Infinity.
Hier ist ein Beispiel, das genau das tun kann. Es ermglicht die Erstellung eines Bereichsiterators, der eine Sequenz von Ganzzahlen von start (einschlielich) bis end (ausschlielich) mit dem Abstand step definiert. Sein endgltiger Rckgabewert ist die Gre der von ihm erstellten Sequenz, die durch die Variable iterationCount verfolgt wird.
function makeRangeIterator(start = 0, end = Infinity, step = 1) {
let nextIndex = start;
let iterationCount = 0;
const rangeIterator = {
next() {
let result;
if (nextIndex < end) {
result = { value: nextIndex, done: false };
nextIndex += step;
iterationCount++;
return result;
}
return { value: iterationCount, done: true };
},
};
return rangeIterator;
}
Die Verwendung des Iterators sieht dann so aus:
const iter = makeRangeIterator(1, 10, 2);
let result = iter.next();
while (!result.done) {
console.log(result.value); // 1 3 5 7 9
result = iter.next();
}
console.log("Iterated over sequence of size:", result.value); // [5 numbers returned, that took interval in between: 0 to 10]
Hinweis: Es ist nicht mglich, reflektiv festzustellen, ob ein bestimmtes Objekt ein Iterator ist. Wenn Sie dies tun mssen, verwenden Sie Iterables.
Obwohl benutzerdefinierte Iteratoren ein ntzliches Werkzeug sind, erfordert ihre Erstellung sorgfltige Programmierung, da ihr interner Zustand explizit gepflegt werden muss. Generatofunktionen bieten eine leistungsstarke Alternative: Sie ermglichen es Ihnen, einen iterativen Algorithmus zu definieren, indem eine einzelne Funktion geschrieben wird, deren Ausfhrung nicht kontinuierlich ist. Generatofunktionen werden mit der function*-Syntax geschrieben.
Bei Aufruf fhren Generatofunktionen ihren Code nicht zunchst aus. Stattdessen geben sie einen speziellen Iteratortyp zurck, der als Generator bezeichnet wird. Wenn ein Wert durch den Aufruf der next-Methode des Generators verbraucht wird, fhrt die Generatofunktion aus, bis sie auf das yield-Schlsselwort trifft.
Die Funktion kann so oft wie gewnscht aufgerufen werden und gibt jedes Mal einen neuen Generator zurck. Jeder Generator kann nur einmal durchlaufen werden.
Wir knnen nun das obige Beispiel anpassen. Das Verhalten dieses Codes ist identisch, aber die Implementierung ist viel einfacher zu schreiben und zu lesen.
function* makeRangeIterator(start = 0, end = Infinity, step = 1) {
let iterationCount = 0;
for (let i = start; i < end; i += step) {
iterationCount++;
yield i;
}
return iterationCount;
}
Ein Objekt ist iterierbar, wenn es sein Iterationsverhalten definiert, wie beispielsweise welche Werte in einer for...of-Konstruktion durchlaufen werden. Einige eingebaute Typen, wie Array oder Map, haben ein Standard-Iterationsverhalten, whrend andere Typen (wie Object) dies nicht tun.
Um iterierbar zu sein, muss ein Objekt die Methode [Symbol.iterator]() implementieren. Das bedeutet, dass das Objekt (oder eines der Objekte in seiner Prototypkette) eine Eigenschaft mit einem Symbol.iterator-Schlssel haben muss.
Es kann mglich sein, ber ein iterierbares Objekt mehrmals oder nur einmal zu iterieren. Es liegt in der Verantwortung des Programmierers zu wissen, welche Variante der Fall ist.
Iterables, die nur einmal iteriert werden knnen (wie Generatoren), geben blicherweise this von ihrer [Symbol.iterator]()-Methode zurck, whrend Iterables, die mehrmals durchlaufen werden knnen, einen neuen Iterator bei jedem Aufruf von [Symbol.iterator]() zurckgeben mssen.
function* makeIterator() {
yield 1;
yield 2;
}
const iter = makeIterator();
for (const itItem of iter) {
console.log(itItem);
}
console.log(iter[Symbol.iterator]() === iter); // true
// This example show us generator(iterator) is iterable object,
// which has the [Symbol.iterator]() method return the `iter` (itself),
// and consequently, the it object can iterate only _once_.
// If we change the [Symbol.iterator]() method of `iter` to a function/generator
// which returns a new iterator/generator object, `iter`
// can iterate many times
iter[Symbol.iterator] = function* () {
yield 2;
yield 1;
};
Sie knnen Ihre eigenen Iterables so erstellen:
const myIterable = {
*[Symbol.iterator]() {
yield 1;
yield 2;
yield 3;
},
};
Benutzerdefinierte Iterables knnen in for...of-Schleifen oder der Spread-Syntax wie blich verwendet werden.
for (const value of myIterable) {
console.log(value);
}
// 1
// 2
// 3
[...myIterable]; // [1, 2, 3]
String, Array, TypedArray, Map und Set sind alle eingebaute Iterables, da ihre Prototypobjekte alle eine Symbol.iterator-Methode haben.
Einige Anweisungen und Ausdrcke erwarten Iterables. Zum Beispiel: die for...of-Schleifen, spread syntax, yield*, und destructuring-Syntax.
for (const value of ["a", "b", "c"]) {
console.log(value);
}
// "a"
// "b"
// "c"
[..."abc"];
// ["a", "b", "c"]
function* gen() {
yield* ["a", "b", "c"];
}
gen().next();
// { value: "a", done: false }
[a, b, c] = new Set(["a", "b", "c"]);
a;
// "a"
Generatoren berechnen ihre yield-Werte bei Bedarf, was es ihnen ermglicht, Sequenzen effizient darzustellen, deren Berechnung aufwndig ist (oder sogar unendliche Sequenzen, wie oben gezeigt).
Die next()-Methode akzeptiert auch einen Wert, der verwendet werden kann, um den internen Zustand des Generators zu ndern. Ein Wert, der an next() bergeben wird, wird von yield empfangen.
Hinweis:
Ein Wert, der bei der ersten Aufruf von next() bergeben wird, wird immer ignoriert.
Hier ist der Fibonacci-Generator, der next(x) verwendet, um die Sequenz neu zu starten:
function* fibonacci() {
let current = 0;
let next = 1;
while (true) {
const reset = yield current;
[current, next] = [next, next + current];
if (reset) {
current = 0;
next = 1;
}
}
}
const sequence = fibonacci();
console.log(sequence.next().value); // 0
console.log(sequence.next().value); // 1
console.log(sequence.next().value); // 1
console.log(sequence.next().value); // 2
console.log(sequence.next().value); // 3
console.log(sequence.next().value); // 5
console.log(sequence.next().value); // 8
console.log(sequence.next(true).value); // 0
console.log(sequence.next().value); // 1
console.log(sequence.next().value); // 1
console.log(sequence.next().value); // 2
Sie knnen einen Generator zwingen, eine Ausnahme auszulsen, indem Sie seine throw()-Methode aufrufen und den Ausnahme-Wert bergeben, den er auslsen soll. Diese Ausnahme wird aus dem aktuellen angehaltenen Kontext des Generators geworfen, als ob der yield, der derzeit angehalten ist, stattdessen eine throw value-Anweisung wre.
Wenn die Ausnahme nicht innerhalb des Generators abgefangen wird, wird sie durch den Aufruf von throw() nach oben propagiert, und nachfolgende Aufrufe von next() fhren dazu, dass die done-Eigenschaft true ist.
Generatoren haben eine return()-Methode, um den angegebenen Wert zurckzugeben und den Generator selbst zu beenden.
Der Bauplan fr ein besseres Internet.
Teile dieses Inhalts sind 19982026 von einzelnen mozilla.org-Mitwirkenden. Inhalte sind verfgbar unter einer Creative-Commons-Lizenz.
| Web Proxy Viewer | New URL | Original Page |