ES2015 fügt Javascript viele neue Funktionen hinzu, die eine Reihe von leistungsfähigen Konstrukten, die in anderen Sprachen schon seit Jahren vorhanden sind, im Browser verfügbar machen (natürlich sobald die Unterstützung für diese Funktionen ausgerollt ist, aber in der Zwischenzeit können wir diese Funktionen mit einem Transpiler wie Babeljs oder Traceur nutzen).
Einige der komplizierteren Ergänzungen sind die Iterator- und Iterable-Protokolle und Generatorfunktionen. In diesem Beitrag erkläre ich, was sie sind und wofür Sie sie verwenden können.
Damit ein Objekt als Iterator betrachtet werden kann, muss es eine Methode namens `next` haben, die ein Objekt mit 2 Eigenschaften zurückgibt: * `value`: Der tatsächliche Wert der Iterationsdatei, die durchlaufen wird. Dies gilt nur, wenn done `false` ist
* `done`: `false`, wenn `value` ein aktueller Wert ist, `true`, wenn der Iterator keinen neuen Wert erzeugt hat
Beachten Sie, dass Sie die Eigenschaft `done` weglassen können, wenn Sie einen `value` angegeben haben, und dass Sie die Eigenschaft `done` weglassen können, wenn sie `true` ist.
Das Objekt, das von der Funktion zurückgegeben wird, die an die Eigenschaft `Symbol.iterator` der DataStructure im vorherigen Beispiel gebunden ist, tut dies, indem es den Eintrag aus dem Array als Value-Eigenschaft zurückgibt und `done: false` zurückgibt, solange noch Einträge im Daten-Array vorhanden sind.
Indem Sie also einfach diese beiden Protokolle implementieren, können Sie jede `Klasse` (oder jedes `Objekt`) in ein Objekt verwandeln, über das Sie iterieren können.
Eine Reihe von Built-Ins in ES2015 implementieren diese Protokolle bereits, so dass Sie sofort mit dem Protokoll experimentieren können. Sie können bereits über Strings, Arrays, TypedArrays, Maps und Sets iterieren.
Die Protokolle Iterable und Iterator
Diese Protokolle sind Analogien zu den Java-Schnittstellen und definieren den Vertrag, den ein Objekt einhalten muss, um als Iterable oder Iterator zu gelten. Es handelt sich also nicht um neue Sprachfeatures, sondern um die Nutzung bestehender Konstrukte durch die Vereinbarung einer Konvention (da Javascript kein Konzept wie eine Schnittstelle in anderen typisierten Sprachen hat). Werfen wir einen genaueren Blick auf diese Protokolle und sehen wir, wie sie miteinander interagieren.Das Iterable-Protokoll
Dieses Protokoll legt fest, dass ein Objekt, das als iterierbar gilt (und z.B. in einer `for ... of`-Schleife verwendet werden kann), eine Funktion mit dem speziellen Schlüssel "Symbol.iterator" definieren muss, die ein Objekt zurückgibt, das dem Iterator-Protokoll entspricht. Das ist im Grunde die einzige Anforderung. Angenommen, Sie haben eine Datenstruktur, über die Sie iterieren möchten. In ES2015 würden Sie das wie folgt tun: [javascript] class DataStructure { constructor(data) { this.data = data; } [Symbol.iterator]() { let current = 0 let data = this.data.slice(); zurück { next: function () { zurück { Wert: data[current++], erledigt: aktuell > data.length }; } } } } let ds = new DataStructure(['hallo', 'Welt']); console.log([...ds]) // ["hallo", "welt"] [/javascript] Der große Vorteil der Verwendung des iterable-Protokolls gegenüber der Verwendung eines anderen Konstrukts wie `for ... in` ist, dass Sie eine klarer definierte Iterationssemantik haben (zum Beispiel: Sie brauchen keine explizite hasOwnProperty-Prüfung, wenn Sie über ein Array iterieren, um Eigenschaften auf dem Array-Objekt, aber nicht im Array herauszufiltern). Ein weiterer Vorteil ist, dass Sie bei der Verwendung von Generatorfunktionen von der "Lazy Evaluation" profitieren können (mehr zu Generatorfunktionen später).Das Iterator-Protokoll
Wie bereits erwähnt, ist die einzige Voraussetzung für das Iterable-Protokoll, dass das Objekt eine Funktion definiert, die einen Iterator zurückgibt. Aber was definiert einen Iterator?Generator-Funktionen
Wie im vorangegangenen Beispiel gezeigt, kann die manuelle Implementierung der Iterable- und Iterator-Protokolle ziemlich mühsam und fehleranfällig sein. Aus diesem Grund wurde in ES2015 eine neue Sprachfunktion hinzugefügt: Generatorfunktionen. Ein Generator kombiniert sowohl eine Iterable als auch einen Iterator in einer einzigen Funktionsdefinition. Eine Generatorfunktion wird deklariert, indem man ein Sternchen (`*`) an den Funktionsnamen anhängt und yield verwendet, um Werte zurückzugeben. Der große Vorteil dieser Methode besteht darin, dass Ihre Generatorfunktion einen Iterator zurückgibt, der beim Aufruf der Methode `next()` bis zur ersten Yield-Anweisung läuft, auf die er stößt, und die Ausführung aussetzt, bis `next()` erneut aufgerufen wird (danach wird er wieder aufgenommen und läuft bis zur nächsten Yield-Anweisung). Auf diese Weise können wir eine Iteration schreiben, die langsam ausgewertet wird, anstatt alles auf einmal. Das folgende Beispiel implementiert die Iterable und den Iterator neu, indem es eine Generatorfunktion verwendet, die das gleiche Ergebnis liefert, aber mit einer prägnanteren Syntax. [javascript] class DataStructure { constructor(data) { this.data = data; } *[Symbol.iterator] () { let data = this.data.slice(); for (let entry of data) { yield entry; } } } let ds = new DataStructure(['hello', 'world']); console.log([...ds]) // ["hello", "world"] [/javascript]Komplexere Verwendungen von Generatoren
Wie bereits erwähnt, ermöglichen Generatorfunktionen eine träge Auswertung von (möglicherweise) unendlichen Iterationen und erlauben die Verwendung von Konstrukten, die aus funktionalen Sprachen bekannt sind, wie z.B. die Auswahl einer begrenzten Teilmenge aus einer unendlichen Sequenz: [javascript] function* generator() { Lassen Sie i = 0; while (true) { Ertrag i++; } } function* take(number, gen) { let current = 0; for (let result of gen) { das Ergebnis; wenn (aktuell++ >= Zahl) { Pause; } } } console.log([...take(10, generator())]) // [0,1,2,3,4,5,6,7,8,9] console.log([...take(10, [1,2,3])]) // [1,2,3] [/javascript] Delegieren von Generatoren Innerhalb eines Generators ist es möglich, an einen zweiten Generator zu delegieren und so rekursive Iterationsstrukturen zu erstellen. Das folgende Beispiel demonstriert einen einfachen Generator, der an einen Untergenerator delegiert und zum Hauptgenerator zurückkehrt. [javascript] function* generator() { yield 1; yield* subGenerator() yield 4; } function* subGenerator() { yield 2; yield 3; } console.log([...generator()]) // [1,2,3,4] [/javascript]Verfasst von
Cristiana
Some bio goes here
Unsere Ideen
Weitere Blogs
Contact
Let’s discuss how we can support your journey.



