Um iterável é o mesmo que um iterador ou eles são diferentes?
Parece que, pelas especificações , um iterável é um objeto, por exemplo, obj
que obj[Symbol.iterator]
se refere a uma função, de modo que, quando invocado, retorna um objeto que possui um next
método que pode retornar um {value: ___, done: ___}
objeto:
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)
Portanto, no código acima, bar
é o iterável, wah
o iterador e a next()
interface do iterador.
Então, iterável e iterador são coisas diferentes.
Agora, no entanto, em um exemplo comum de gerador e iterador:
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
No caso acima, gen1
é o gerador e iter1
o iterador, e iter1.next()
fará o trabalho adequado. Mas iter1[Symbol.iterator]
fornece uma função que, quando invocada, devolve iter1
, que é um iterador. Então, iter1
é um iterável e um iterador nesse caso?
Além disso, iter1
é diferente do exemplo 1 acima, porque o iterável no exemplo 1 pode fornecer [1, 3, 5]
quantas vezes quiser [...bar]
, enquanto iter1
é iterável, mas como ele retorna, que é o mesmo iterador todas as vezes, dará apenas [1, 3, 5]
uma vez.
Então, podemos dizer, de forma iterável bar
, quantas vezes podem [...bar]
dar o resultado [1, 3, 5]
- e a resposta é: depende. E é iterável o mesmo que um iterador? E a resposta é: são coisas diferentes, mas podem ser as mesmas quando o iterável se usa como iterador. Isso está correto?
fonte
iter1
é um iterável e um iterador neste caso? " - sim. Todos os iteradores nativos também são iteráveis retornando a si mesmos, para que você possa transmiti-los facilmente para construções que esperam ser iteráveis.Respostas:
Sim, iterables e iteradores são coisas diferentes, mas a maioria dos iteradores (incluindo todas as que você recebe do próprio JavaScript, como a dos
keys
ouvalues
métodos emArray.prototype
ou geradores de funções de gerador) herdam a % IteratorPrototype% objeto , que tem umSymbol.iterator
método como isto:O resultado é que todos os iteradores padrão também são iteráveis. É assim que você pode usá-los diretamente ou usá-los em
for-of
loops e outros (que esperam iteráveis, não iteradores).Considere o
keys
método de matrizes: ele retorna um iterador de matriz que visita as chaves da matriz (seus índices, como números). Observe que ele retorna um iterador . Mas um uso comum é:for-of
leva um iterável , não um iterador , então por que isso funciona?Funciona porque o iterador também é iterável;
Symbol.iterator
apenas retornathis
.Aqui está um exemplo que eu uso no capítulo 6 do meu livro: se você quiser fazer um loop sobre todas as entradas, mas pular a primeira e não desejar
slice
cortar o subconjunto, poderá obter o iterador, ler o primeiro valor, então entregue a umfor-of
loop:Observe que isso são todos os iteradores padrão . Em algum momento, as pessoas mostram exemplos de iteradores codificados manualmente como este:
Mostrar snippet de código
O iterador retornado por
range
lá é não um iterável, por isso falhar quando tentamos usá-lo comfor-of
.Para torná-lo iterável, precisamos:
Symbol.iterator
método no início da resposta acima a ele ouInfelizmente, o TC39 decidiu não fornecer uma maneira direta de obter o objeto% IteratorPrototype%. Existe uma maneira indireta (obter um iterador de uma matriz e, em seguida, pegar seu protótipo, que é definido como% IteratorPrototype%), mas é uma dor.
Mas não há necessidade de escrever iteradores manualmente assim; basta usar uma função de gerador, pois o gerador que ele retorna é iterável:
Mostrar snippet de código
Por outro lado, nem todos os iteráveis são iteradores. Matrizes são iteráveis, mas não iteradoras. O mesmo acontece com seqüências de caracteres, mapas e conjuntos.
fonte
Descobri que existem algumas definições mais precisas dos termos e estas são as respostas mais definitivas:
De acordo com as especificações ES6 e MDN :
Quando temos
foo
é chamado de função de gerador . E então quando tivermosbar
é um objeto gerador . E um objeto gerador está em conformidade com o protocolo iterável e o protocolo iterador .A versão mais simples é a interface do iterador, que é apenas um
.next()
método.O protocolo iterável é: para o objeto
obj
,obj[Symbol.iterator]
fornece uma "função de zero argumentos que retorna um objeto, em conformidade com o protocolo do iterador".Pelo título do link MDN , também parece que também podemos chamar um objeto gerador de "gerador".
Observe que no livro de Nicolas Zakas, Entendendo o ECMAScript 6 , ele provavelmente chamou vagamente uma "função geradora" como "gerador" e um "objeto gerador" como "iterador". O ponto de partida é que ambos são realmente "geradores" - um é uma função de gerador e outro é um objeto gerador, ou gerador. O objeto gerador está em conformidade com o protocolo iterável e o protocolo iterador.
Se for apenas um objeto em conformidade com o protocolo do iterador , você não poderá usar
[...iter]
oufor (a of iter)
. Tem que ser um objeto que esteja em conformidade com o protocolo iterável .E também há uma nova classe Iterator, em futuras especificações de JavaScript que ainda estão em rascunho . Ele tem uma interface maior, incluindo métodos tais como
forEach
,map
,reduce
da interface matriz atual, e os novos, como etake
, edrop
. O iterador atual refere-se ao objeto apenas com anext
interface.Para responder à pergunta original: qual é a diferença entre um iterador e um iterável, a resposta é: um iterador é um objeto com a interface
.next()
e um iterável é um objetoobj
queobj[Symbol.iterator]
pode fornecer uma função de argumento zero que, quando invocada, retorna um iterador.E um gerador é um iterável e um iterador, para adicionar a isso.
fonte