1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
|
---
title: Iteratores e geradores
slug: Web/JavaScript/Guide/Iterators_and_Generators
tags:
- Generators
- Guia(2)
- Intermediario(2)
- Iteradores
- JavaScript
translation_of: Web/JavaScript/Guide/Iterators_and_Generators
original_slug: Web/JavaScript/Guide/Iteratores_e_geradores
---
<div>{{jsSidebar("JavaScript Guide")}} {{PreviousNext("Web/JavaScript/Guide/Details_of_the_Object_Model", "Web/JavaScript/Guide/Meta_programming")}}</div>
<p class="summary">Processar cada item em uma coleção é uma operação muito comum. O JavaScript disponibiliza uma série de maneiras de iterar sobre uma coleção, desde um simples laço {{jsxref("Statements/for","for")}}, até um {{jsxref("Global_Objects/Array/map","map()")}} e também com o {{jsxref("Global_Objects/Array/filter","filter()")}}. Iteradores e Geradores trazem o conceito da interação ocorrer diretamente no núcleo da linguagem e prover um mecanismo para a customização do comportamento dos laços {{jsxref("Statements/for...of","for...of")}}.</p>
<p>Para detalhes, também veja:</p>
<ul>
<li><a href="/en-US/docs/Web/JavaScript/Reference/Iteration_protocols">Protocolos de iteração</a></li>
<li>{{jsxref("Statements/for...of","for...of")}}</li>
<li>{{jsxref("Statements/function*","function*")}} e {{jsxref("Generator")}}</li>
<li>{{jsxref("Operators/yield","yield")}} e {{jsxref("Operators/yield*","yield*")}}</li>
</ul>
<h2 id="Iterators_Iteradores">Iterators (Iteradores)</h2>
<p>Um objeto é um <strong>iterator (iterador)</strong> quando sabe como acessar itens numa coleção, um por vez, enquanto mantém rastreada a posição atual em uma dada sequência. Em JavaScript um iterator é um objeto que oferece o método <code>next(),</code> o qual retorna o próximo item da sequência. Este método retorna um objeto com duas propriedades: <code>done</code> e <code>value</code>.</p>
<p>Uma vez criado, um objeto iterator pode ser usado explicitamente ao chamar repetidas vezes o método <code>next()</code>.</p>
<pre class="brush: js notranslate">const makeIterator = (array) => {
let nextIndex = 0;
return {
next : () => {
return nextIndex < array.length ?
{value: array[nextIndex ++], done: false} :
{done: true};
}
}
};</pre>
<p>Uma vez inicializado, o método <code>next()</code> pode ser chamado para acessar os pares chave/valor do objeto da vez.</p>
<pre class="brush: js notranslate">let it = makeIterator(['yo', 'ya']);
console.log(it.next().value); // 'yo'
console.log(it.next().value); // 'ya'
console.log(it.next().done); // true</pre>
<h2 id="Iterables_Iteráveis">Iterables (Iteráveis)</h2>
<p>Um objeto é iterável <strong>(iterable),</strong> se ele define seu comportamento de iteração, como no caso de quais valores percorridos em um laço do tipo {{jsxref("Statements/for...of", "for..of")}}. Alguns tipos embutidos, como o {{jsxref("Array")}}, ou o {{jsxref("Map")}}, têm um comportamento iterável padrão, enquanto outros tipos (como o{{jsxref("Object")}}) não possuem.</p>
<p>Para que um objeto seja <strong>iterable</strong>, o objeto precisa implementar o método <strong>@@iterator</strong>, significando que o objeto (ou um dos objetos na cadeia de prototipagem - <a href="/en-US/docs/Web/JavaScript/Guide/Inheritance_and_the_prototype_chain">prototype chain</a>) precisa ter uma propriedade com uma chave {{jsxref("Symbol.iterator")}}:</p>
<h3 id="Iterables_definidos_pelo_usuário">Iterables definidos pelo usuário</h3>
<p>Você pode fazer seus próprios iteráveis da seguinte maneira:</p>
<pre class="brush: js notranslate">var myIterable = {}
myIterable[Symbol.iterator] = function* () {
yield 1;
yield 2;
yield 3;
};
[...myIterable] // [1, 2, 3]
</pre>
<h3 id="Iterables_Built-in_Iteráveis_Embutidos">Iterables Built-in (Iteráveis Embutidos)</h3>
<p>{{jsxref("String")}}, {{jsxref("Array")}}, {{jsxref("TypedArray")}}, {{jsxref("Map")}} e {{jsxref("Set")}} são iteráveis embutidos, pois o protótipo dos objetos de todos eles têm o método {{jsxref("Symbol.iterator")}}.</p>
<h3 id="Syntaxes_expecting_iterables">Syntaxes expecting iterables</h3>
<p>Algumas declarações e expressões esperam por iteradores, por exemplo o {{jsxref("Statements/for...of","for-of")}} loops, {{jsxref("Operators/Spread_operator","spread operator","","true")}}, {{jsxref("Operators/yield*","yield*")}}, e {{jsxref("Operators/Destructuring_assignment","destructuring assignment","","true")}}.</p>
<pre class="brush: js notranslate">for(let 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"
</pre>
<h2 id="Generators">Generators</h2>
<p>Enquanto os iteradores são ferramentas muito úteis, sua criação requer um cuidado devido à necessidade de manter explícito seu estado interno. <strong>{{jsxref("Global_Objects/Generator","Generators","","true")}}</strong> provêm uma alternativa poderosa: eles te permitem definir um algorítimo iterativo escrevendo uma função simples que pode manter seu estado próprio.</p>
<p>Generator é um tipo especial de função que trabalha como uma factory para iteradores. A função vira um generator se ela contém uma ou mais expressões {{jsxref("Operators/yield","yield")}} e se ela usa a sintaxe {{jsxref("Statements/function*","function*")}}.</p>
<pre class="brush: js notranslate">function* idMaker(){
var index = 0;
while(true)
yield index++;
}
var gen = idMaker();
console.log(gen.next().value); // 0
console.log(gen.next().value); // 1
console.log(gen.next().value); // 2
// ...</pre>
<h2 id="Generators_avançados">Generators avançados</h2>
<p>Generators computam seus valores "yielded" por demanda, que os permitem representar sequências de forma eficiente que costumam ser trabalhosas ao serem computadas, ou até sequências infinitas como demonstradas acima.</p>
<p>O método {{jsxref("Global_Objects/Generator/next","next()")}} também aceita um valor que pode ser usado para modificar o estado interno de um generator. O valor passado pro <code>next()</code> será tratado como o resultado da última expressão yield que pausou o generator.</p>
<p>Aqui um gerador de sequência Fibonacci usando <code>next(x)</code> pra restartar a sequência:</p>
<pre class="brush: js notranslate">function* fibonacci(){
var fn1 = 1;
var fn2 = 1;
while (true){
var current = fn2;
fn2 = fn1;
fn1 = fn1 + current;
var reset = yield current;
if (reset){
fn1 = 1;
fn2 = 1;
}
}
}
var sequence = fibonacci();
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().value); // 13
console.log(sequence.next(true).value); // 1
console.log(sequence.next().value); // 1
console.log(sequence.next().value); // 2
console.log(sequence.next().value); // 3</pre>
<div class="note"><strong>Nota:</strong> Como um ponto de interesse, chamando <code>next(undefined)</code> é o mesmo que chamar <code>next()</code>. Entretanto, estartar um novo generator com qualquer valor que não seja undefined na chamada next() terá <code>TypeError</code> exception.</div>
<p>Você pode forçar um generator a lançar uma exceção chamando o seu método {{jsxref("Global_Objects/Generator/throw","throw()")}} e passando o valor da exceção que ele deve lançar. Essa exceção será lançada do contexto suspenso atual do generator, como se o <code>yield</code> atualmente suspenso fosse um <code>throw</code>.</p>
<p>Se um yield não for encontrado durante o processo de lançamento de um thrown exception, então o exception será propagado através da chamada do <code>throw()</code>, e pra subsequente chamada do <code>next()</code> que terá a propriedade done resultando em <code>true</code>.</p>
<p>Generators têm o método {{jsxref("Global_Objects/Generator/return","return(value)")}} que retorna o valor pego e finaliza o generator.</p>
<p>{{PreviousNext("Web/JavaScript/Guide/Details_of_the_Object_Model", "Web/JavaScript/Guide/Meta_programming")}}</p>
|