Un itérable est-il le même qu'un itérateur, ou sont-ils différents?
Il semble, d' après les spécifications , qu'un itérable est un objet, disons, obj
tel qu'il obj[Symbol.iterator]
fait référence à une fonction, de sorte que lorsqu'il est invoqué, retourne un objet qui a une next
méthode qui peut retourner un {value: ___, done: ___}
objet:
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)
Donc, dans le code ci-dessus, bar
est l'itérable, et wah
est l'itérateur, et next()
est l'interface d'itérateur.
Donc, itérable et itérateur sont des choses différentes.
Maintenant, cependant, dans un exemple courant de générateur et d'itérateur:
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
Dans le cas ci-dessus, gen1
est le générateur et iter1
l'itérateur, et iter1.next()
fera le bon travail. Mais iter1[Symbol.iterator]
donne une fonction qui, lorsqu'elle est invoquée, donne en retour iter1
, qui est un itérateur. iter1
Est donc à la fois un itérable et un itérateur dans ce cas?
En outre, iter1
est différent de l'exemple 1 ci-dessus, car l'itérable de l'exemple 1 peut donner [1, 3, 5]
autant de fois que souhaité en utilisant [...bar]
, tandis que iter1
est un itérable, mais puisqu'il retourne lui-même, qui est le même itérateur à chaque fois, ne donnera [1, 3, 5]
qu'une seule fois.
Nous pouvons donc dire, pour un itérable bar
, combien de fois peut [...bar]
donner le résultat [1, 3, 5]
- et la réponse est, cela dépend. Et est-il itérable comme un itérateur? Et la réponse est, ce sont des choses différentes, mais elles peuvent être les mêmes, lorsque l'itérable se sert lui-même d'itérateur. Est-ce exact?
la source
iter1
est-ce à la fois un itérable et un itérateur dans ce cas? " - oui. Tous les itérateurs natifs sont également itérables en se retournant, de sorte que vous pouvez facilement les passer dans des constructions qui attendent un itérable.Réponses:
Oui, iterables et itérateurs sont des choses différentes, mais la plupart des itérateurs (y compris tous ceux que vous obtenez de JavaScript lui - même, comme des
keys
ouvalues
méthodes surArray.prototype
ou générateurs de fonctions du générateur) Hériter de l' objet% IteratorPrototype% de , qui a uneSymbol.iterator
méthode comme cette:Le résultat est que tous les itérateurs standard sont également des itérables. C'est ainsi que vous pouvez les utiliser directement, ou les utiliser dans des
for-of
boucles et autres (qui attendent des itérables, pas des itérateurs).Considérez la
keys
méthode des tableaux: il retourne un itérateur de tableau qui visite les clés du tableau (ses index, sous forme de nombres). Notez qu'il retourne un itérateur . Mais une utilisation courante de celui-ci est:for-of
prend un itérable , pas un itérateur , alors pourquoi ça marche?Cela fonctionne parce que l'itérateur est également itérable;
Symbol.iterator
revient justethis
.Voici un exemple que j'utilise dans le chapitre 6 de mon livre: si vous vouliez parcourir toutes les entrées mais sauter la première et que vous ne vouliez pas utiliser
slice
pour couper le sous-ensemble, vous pouvez obtenir l'itérateur, lire la première valeur, puis passez à unefor-of
boucle:Notez que ce sont tous des itérateurs standard . Parfois, les gens montrent des exemples d'itérateurs codés manuellement comme celui-ci:
Afficher l'extrait de code
L'itérateur retourné par
range
là n'est pas un itérable, donc il échoue lorsque nous essayons de l'utiliser avecfor-of
.Pour le rendre itérable, nous devons:
Symbol.iterator
méthode au début de la réponse ci-dessus, ouMalheureusement, TC39 a décidé de ne pas fournir un moyen direct d'obtenir l'objet% IteratorPrototype%. Il existe un moyen indirect (obtenir un itérateur à partir d'un tableau, puis prendre son prototype, qui est défini comme% IteratorPrototype%), mais c'est pénible.
Mais il n'est pas nécessaire d'écrire des itérateurs manuellement comme ça de toute façon; utilisez simplement une fonction de générateur, puisque le générateur qu'il renvoie est itérable:
Afficher l'extrait de code
En revanche, tous les itérables ne sont pas des itérateurs. Les tableaux sont itérables, mais pas les itérateurs. Il en va de même pour les chaînes, les cartes et les ensembles.
la source
J'ai trouvé qu'il existe des définitions plus précises des termes, et ce sont les réponses les plus définitives:
Selon les spécifications ES6 et MDN :
Quand nous avons
foo
est appelé fonction de générateur . Et puis quand nous avonsbar
est un objet générateur . Et un objet générateur est conforme à la fois au protocole itérable et au protocole itérateur .La version la plus simple est l'interface de l'itérateur, qui n'est qu'une
.next()
méthode.Le protocole itérable est: pour l'objet
obj
,obj[Symbol.iterator]
donne une "fonction zéro argument qui renvoie un objet, conforme au protocole itérateur".Par le titre du lien MDN , il semble également que nous puissions également appeler un objet générateur un "générateur".
Notez que dans le livre de Nicolas Zakas Understanding ECMAScript 6 , il a probablement appelé de manière lâche une "fonction de générateur" comme un "générateur" et un "objet générateur" comme un "itérateur". Le point à retenir est qu'ils sont tous deux liés au "générateur" - l'un est une fonction de générateur et l'autre est un objet générateur, ou générateur. L'objet générateur est conforme à la fois au protocole itératif et au protocole itérateur.
S'il s'agit simplement d'un objet conforme au protocole itérateur , vous ne pouvez pas utiliser
[...iter]
oufor (a of iter)
. Il doit s'agir d'un objet conforme au protocole itérable .Et puis, il y a aussi une nouvelle classe Iterator, dans une future spécification JavaScript qui est toujours en projet . Il dispose d' une interface plus grande, y compris des méthodes telles que
forEach
,map
,reduce
de l'interface Array en cours et nouveaux, tels que ettake
, etdrop
. L'itérateur actuel fait référence à l'objet avec juste l'next
interface.Pour répondre à la question d'origine: quelle est la différence entre un itérateur et un itérable, la réponse est: un itérateur est un objet avec l'interface
.next()
, et un itérable est un objetobj
tel qu'ilobj[Symbol.iterator]
peut donner une fonction à zéro argument qui, lorsqu'elle est invoquée, renvoie un itérateur.Et un générateur est à la fois un itérable et un itérateur, pour ajouter à cela.
la source