Ist ein Iterable dasselbe wie ein Iterator oder unterscheiden sie sich?
Es scheint, von den Vorgaben , ein iterable ein Objekt ist, sagen wir, ist obj
, so dass obj[Symbol.iterator]
auf eine Funktion verweist, so dass , wenn aufgerufen, gibt ein Objekt , das eine hat next
Methode , die eine Rückkehr kann {value: ___, done: ___}
Objekt:
function foo() {
let i = 0;
const wah = {
next: function() {
if (i <= 2) return { value: (1 + 2 * i++), done: false }
else return { value: undefined, done: true }
}
};
return wah; // wah is iterator
}
let bar = {} // bar is iterable
bar[Symbol.iterator] = foo;
console.log([...bar]); // [1, 3, 5]
for (a of bar) console.log(a); // 1 3 5 (in three lines)
Im obigen Code bar
ist also die Iterierbarkeit und wah
der Iterator und next()
die Iteratorschnittstelle.
Iterable und Iterator sind also verschiedene Dinge.
Nun jedoch zu einem gängigen Beispiel für Generator und Iterator:
function* gen1() {
yield 1;
yield 3;
yield 5;
}
const iter1 = gen1();
console.log([...iter1]); // [1, 3, 5]
for (a of iter1) console.log(a); // nothing
const iter2 = gen1();
for (a of iter2) console.log(a); // 1 3 5 (in three lines)
console.log(iter1[Symbol.iterator]() === iter1); // true
Im obigen Fall gen1
ist der Generator und iter1
der Iterator und iter1.next()
erledigt die richtige Arbeit. Gibt iter1[Symbol.iterator]
aber eine Funktion, die beim Aufrufen etwas zurückgibt iter1
, was ein Iterator ist. So iter1
ist sowohl ein iterable und Iterator in diesem Fall?
Außerdem iter1
unterscheidet es sich von dem obigen Beispiel 1, weil das Iterable in Beispiel 1 [1, 3, 5]
so oft geben kann, wie es gewünscht wird [...bar]
, während iter1
es ein Iterable ist, aber da es sich selbst zurückgibt, das jedes Mal der gleiche Iterator ist, gibt es nur [1, 3, 5]
einmal.
Wir können also für eine Iterable sagen, bar
wie oft [...bar]
das Ergebnis erzielt werden kann [1, 3, 5]
- und die Antwort ist, es hängt davon ab. Und ist iterierbar dasselbe wie ein Iterator? Und die Antwort ist, sie sind verschiedene Dinge, aber sie können gleich sein, wenn sich das Iterable selbst als Iterator verwendet. Ist das korrekt?
quelle
iter1
ist in diesem Fall sowohl ein Iterator als auch ein Iterator? " - ja. Alle nativen Iteratoren können auch iteriert werden, indem sie sich selbst zurückgeben, sodass Sie sie problemlos an Konstrukte übergeben können, die eine Iterierbarkeit erwarten.Antworten:
Ja, Iterables und Iteratoren sind verschiedene Dinge, aber die meisten Iteratoren (einschließlich aller Iteratoren, die Sie von JavaScript selbst erhalten, z. B. von den Methoden
keys
odervalues
MethodenArray.prototype
oder Generatoren von Generatorfunktionen) erben von Objekt% IteratorPrototype% , das eineSymbol.iterator
Methode wie diese hat diese:Das Ergebnis ist, dass alle Standarditeratoren auch iterabel sind. Auf diese Weise können Sie sie direkt oder in
for-of
Schleifen und dergleichen verwenden (die iterable, keine Iteratoren erwarten).Betrachten Sie die
keys
Methode von Arrays: Es wird ein Array-Iterator zurückgegeben, der die Schlüssel des Arrays (seine Indizes als Zahlen) besucht. Beachten Sie, dass ein Iterator zurückgegeben wird . Aber eine übliche Verwendung davon ist:for-of
nimmt eine iterable , keinen Iterator . Warum funktioniert das?Es funktioniert, weil der Iterator auch iterierbar ist.
Symbol.iterator
kehrt gerade zurückthis
.Hier ist ein Beispiel, das ich in Kapitel 6 meines Buches verwende: Wenn Sie alle Einträge durchlaufen, aber den ersten überspringen möchten
slice
und die Teilmenge nicht abschneiden möchten , können Sie den Iterator abrufen, den ersten Wert lesen. dann an einefor-of
Schleife übergeben:Beachten Sie, dass dies alles Standarditeratoren sind . Manchmal zeigen Leute Beispiele für manuell codierte Iteratoren wie diese:
Code-Snippet anzeigen
Der von
range
dort zurückgegebene Iterator ist nicht iterierbar, daher schlägt er fehl, wenn wir versuchen, ihn mit zu verwendenfor-of
.Um es iterierbar zu machen, müssten wir entweder:
Symbol.iterator
Methode am Anfang der obigen Antwort hinzu, oderLeider hat TC39 beschlossen, keinen direkten Weg zum Abrufen des% IteratorPrototype% -Objekts bereitzustellen. Es gibt einen indirekten Weg (einen Iterator aus einem Array abrufen und dann seinen Prototyp nehmen, der als% IteratorPrototype% definiert ist), aber es ist ein Schmerz.
Aber es ist sowieso nicht nötig, solche Iteratoren manuell zu schreiben. Verwenden Sie einfach eine Generatorfunktion, da der zurückgegebene Generator iterierbar ist:
Code-Snippet anzeigen
Im Gegensatz dazu sind nicht alle Iterables Iteratoren. Arrays sind iterierbar, aber keine Iteratoren. Dies gilt auch für Zeichenfolgen, Karten und Mengen.
quelle
Ich fand heraus, dass es einige genauere Definitionen der Begriffe gibt, und dies sind die endgültigeren Antworten:
Gemäß den ES6-Spezifikationen und dem MDN :
Wenn wir haben
foo
genannt ist Generatorfunktion . Und dann, wenn wir habenbar
ist ein Generator - Objekt . Und ein Generator - Objekt Konform sowohl auf das iterable - Protokoll und das Iterator - Protokoll .Die einfachere Version ist die Iterator-Schnittstelle, die nur eine ist
.next()
Methode ist.Das iterierbare Protokoll lautet: für das Objekt
obj
,obj[Symbol.iterator]
gibt ein „Null - Argumente Funktion, gibt ein Objekt, auf das Iterator - Protokoll konform“.Durch den Titel des MDN-Links können wir ein Generatorobjekt auch einfach als "Generator" bezeichnen.
Beachten Sie, dass er in Nicolas Zakas 'Buch Understanding ECMAScript 6 wahrscheinlich lose eine "Generatorfunktion" als "Generator" und ein "Generatorobjekt" als "Iterator" bezeichnet hat. Der Take-Away-Punkt ist, dass beide wirklich "Generator" -bezogen sind - eine ist eine Generatorfunktion und eine ist ein Generatorobjekt oder Generator. Das Generatorobjekt entspricht sowohl dem iterierbaren Protokoll als auch dem Iteratorprotokoll.
Wenn es nur ein Objekt auf das konforme Iterator - Protokoll, Sie können nicht verwenden
[...iter]
oderfor (a of iter)
. Es muss ein Objekt sein, das dem iterierbaren Protokoll entspricht.Und dann gibt es noch eine neue Iterator-Klasse in zukünftigen JavaScript-Spezifikationen, die sich noch in einem Entwurf befindet . Es hat eine größere Oberfläche, einschließlich Verfahrens , wie zum Beispiel
forEach
,map
,reduce
des aktuellen Array - Schnittstelle und neuen, wie undtake
, unddrop
. Der aktuelle Iterator bezieht sich nur auf das Objekt mit dernext
Schnittstelle.Um die ursprüngliche Frage zu beantworten: Was ist der Unterschied zwischen einem Iterator und einer abzählbaren, lautet die Antwort: ein Iterator ist ein Objekt mit der Schnittstelle
.next()
und ein iterable ist ein Objekt ,obj
so dassobj[Symbol.iterator]
eine Null-Argument Funktion geben kann , dass, wenn sie aufgerufen wird , Gibt einen Iterator zurück.Und ein Generator ist sowohl iterierbar als auch iteratorisch.
quelle