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
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
|
---
title: function*
slug: Web/JavaScript/Reference/Statements/function*
tags:
- ECMAScript6
- Function
- Iterator
- JavaScript
- Statement
translation_of: Web/JavaScript/Reference/Statements/function*
---
<div>{{jsSidebar("Statements")}}</div>
<p>A declaração <code><strong>function*</strong></code> (palavra chave <code>function</code> seguida de um asterisco) define uma <em>função geradora</em> (<em>generator function</em>), que retorna um objeto {{jsxref("Global_Objects/Generator","Generator")}}.</p>
<p>{{EmbedInteractiveExample("pages/js/statement-functionasterisk.html")}}</p>
<p>Você também pode definir funções geradoras usando o construtor {{jsxref("GeneratorFunction")}} ou a sintaxe da expressão de uma função. </p>
<h2 id="Syntax" name="Syntax">Sintaxe</h2>
<pre class="syntaxbox notranslate">function* <em>name</em>([<em>param</em>[, <em>param</em>[, ... <em>param</em>]]]) {
<em>statements</em>
}</pre>
<dl>
<dt><code>name</code></dt>
<dd>O nome da função.</dd>
</dl>
<dl>
<dt><code>param</code></dt>
<dd>O nome do argumento que será passado á função. Uma função pode ter até 255 argumentos.</dd>
</dl>
<dl>
<dt><code>statements</code></dt>
<dd>As instruções que formam o corpo da função.</dd>
</dl>
<h2 id="Descrição">Descrição</h2>
<p>Geradores são funções cuja execução pode ser interrompida e posteriormente reconduzida. Seus contextos (de associações de variáveis) ficarão salvos entre cada recondução.</p>
<p>Geradores em JavaScript -- especialmente quando combinados com <em>Promises </em>-- são uma ferramenta muito poderosa para programação assíncrona, por mitigarem -- se não eliminarem -- problemas com callbacks, como o <a href="http://callbackhell.com/">Callback Hell</a> e <a href="https://frontendmasters.com/courses/rethinking-async-js/callback-problems-inversion-of-control/">Inversão de Controle</a>. Funções <code><a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function">async</a></code> são fundamentadas nisso.</p>
<p>Chamar uma função geradora não executa seu conteúdo imediatamente; ao invés disso um objeto <em><a href="/en-US/docs/Web/JavaScript/Guide/The_Iterator_protocol">iterator</a></em> é retornado. Quando o método <code>next()</code> do objeto <em>iterator</em> é chamado, o conteúdo da função do gerador é executado até a primeira expressão {{jsxref("Operators/yield", "yield")}}, que especifica o valor a ser devolvido do <em>iterator </em>ou com {{jsxref("Operators/yield*", "yield*")}} que delega para outra função geradora. O método <code style="font-style: normal; line-height: 1.5;">next()</code><span style="line-height: 1.5;"> retorna um objeto com uma propriedade </span><code><span style="font-family: consolas,monaco,andale mono,monospace; line-height: 1.5;">value</span></code><span style="line-height: 1.5;"> contendo o valor retornado e a propriedade <em>boolean</em>: </span><code><span style="font-family: consolas,monaco,andale mono,monospace; line-height: 1.5;">done</span></code><span style="line-height: 1.5;"> indicando se o gerador produziu seu último valor. Chamar o método <code>next()</code> com um argumento resumirá a execução da função geradora, substituindo a expressão <code>yield</code> onde a execução foi pausada com o argumento de <code>next()</code>.</span></p>
<p><span style="line-height: 1.5;">Uma expressão <code>return</code> em um gerador, quando executada, fará com que o gerador termine (isto é, a propriedade <code>done</code> do objeto retornado será atribuído com o valor <code>true</code>). Se um valor foi retornado, este será usado como propriedade <code>value</code> do objeto retornado pelo gerador. Semelhantemente a uma expressão <code>return</code>, um erro lançado dentro do gerador o terminará -- a não ser que tratado no corpo do gerador. Quando um gerador estiver terminado, chamadas <code>next</code> subsequentes não executarão nenhum código do gerador, retornarão simplesmente um objeto da seguinte forma: <code>{value: undefined, done: true}</code>.</span></p>
<h2 id="Exemplos">Exemplos</h2>
<h3 id="Exemplo_simples">Exemplo simples</h3>
<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
<code>console.log(gen.next().value); // 3</code>
// ...</pre>
<h3 id="Exemplo_com_yield*">Exemplo com yield*</h3>
<pre class="brush: js notranslate">function* outroGerador(i) {
yield i + 1;
yield i + 2;
yield i + 3;
}
function* gerador(i){
yield i;
yield* outroGerador(i);
yield i + 10;
}
var gen = gerador(10);
console.log(gen.next().value); // 10
console.log(gen.next().value); // 11
console.log(gen.next().value); // 12
console.log(gen.next().value); // 13
console.log(gen.next().value); // 20
</pre>
<h3 id="Passando_argumentos_em_geradores">Passando argumentos em geradores</h3>
<pre class="notranslate"><code>function* logGenerator() {
console.log(0);
console.log(1, yield);
console.log(2, yield);
console.log(3, yield);
}
var gen = logGenerator();
// a primeira chamada next é executada desde o início da função
// até a primeira declaração yield
gen.next(); // 0
gen.next('pretzel'); // 1 pretzel
gen.next('california'); // 2 california
gen.next('mayonnaise'); // 3 mayonnaise</code></pre>
<h3 id="Declaração_de_retono_em_um_gerador">Declaração de retono em um gerador</h3>
<pre class="notranslate"><code>function* yieldAndReturn() {
yield "Y";
return "R";
yield "unreachable";
}
var gen = yieldAndReturn()
console.log(gen.next()); // { value: "Y", done: false }
console.log(gen.next()); // { value: "R", done: true }
console.log(gen.next()); // { value: undefined, done: true }</code></pre>
<h3 id="Geradores_não_possuem_construtor">Geradores não possuem construtor</h3>
<pre class="notranslate"><code>function* f() {}
var obj = new f; // lança o TypeError: f não é construtor</code></pre>
<h3 id="Gerador_definido_em_uma_expressão">Gerador definido em uma expressão</h3>
<pre class="notranslate"><code>const foo = function* () {
yield 10;
yield 20;
};
const bar = foo();
console.log(bar.next()); // {value: 10, done: false}</code></pre>
<h2 id="Specifications" name="Specifications">Especificações</h2>
<table class="standard-table">
<thead>
<tr>
<th scope="col">Especificação</th>
<th scope="col">Status</th>
<th scope="col">Comentário</th>
</tr>
</thead>
<tbody>
<tr>
<td>{{SpecName('ES2015', '#sec-generator-function-definitions', 'function*')}}</td>
<td>{{Spec2('ES2015')}}</td>
<td>Definição inicial.</td>
</tr>
<tr>
<td>{{SpecName('ES2016', '#sec-generator-function-definitions', 'function*')}}</td>
<td>{{Spec2('ES2016')}}</td>
<td>Mudou para que <em>generators </em>não tenham a armadilha de [[Construct]] e irão lançar um erro, quando usados com <code>new</code>.</td>
</tr>
<tr>
<td>{{SpecName('ESDraft', '#sec-generator-function-definitions', 'function*')}}</td>
<td>{{Spec2('ESDraft')}}</td>
<td></td>
</tr>
</tbody>
</table>
<h2 id="Browser_compatibility">Compatibilidade com navegadores</h2>
<div id="compat-mobile">{{Compat("javascript.statements.generator_function")}}</div>
<h2 id="Observações_específicas_Firefox">Observações específicas Firefox</h2>
<h4 id="Generators_e_iterators_no_Firefox_em_versões_anteriores_a_26">Generators e iterators no Firefox em versões anteriores a 26</h4>
<p>Versões mais antigas do Firefox implementam uma versão antiga da proposta de <em>generators</em>. Na versão mais antiga, <em>generators </em>foram intruídos a usarem a palavra chave <code>function</code>(sem um asterísco) dentre outras diferenças.</p>
<h4 id="O_retorno_do_objeto_IteratorResult_ao_invés_de_um_throw">O retorno do objeto <code>IteratorResult</code> ao invés de um throw</h4>
<p>Iniciando com Gecko 29 {{geckoRelease(29)}}, o <em>generator </em>finalizado não lança mais um {{jsxref("TypeError")}} "generator has already finished". Ao invés disso, ele retorna um objeto <code>IteratorResult</code>, como por exemplo <code>{ value: undefined, done: true }</code> ({{bug(958951)}}).</p>
<h2 id="Veja_também">Veja também</h2>
<ul>
<li>{{jsxref("Operators/function*", "function* expression")}}</li>
<li>{{jsxref("GeneratorFunction")}} object</li>
<li><a href="/en-US/docs/Web/JavaScript/Guide/The_Iterator_protocol">The Iterator protocol</a></li>
<li>{{jsxref("Operators/yield", "yield")}}</li>
<li>{{jsxref("Operators/yield*", "yield*")}}</li>
<li>{{jsxref("Function")}} object</li>
<li>{{jsxref("Statements/function", "function declaration")}}</li>
<li>{{jsxref("Operators/function", "function expression")}}</li>
<li>{{jsxref("Functions_and_function_scope", "Functions and function scope")}}</li>
<li>Outras fontes na web:
<ul>
<li><a href="http://facebook.github.io/regenerator/">Regenerator</a> um ES6 generator que compila para ES5</li>
<li><a href="http://www.youtube.com/watch?v=qbKWsbJ76-s">Forbes Lindesay: Promises and Generators: control flow utopia -- JSConf EU 2013</a></li>
<li><a href="https://www.youtube.com/watch?v=ZrgEZykBHVo&list=PLuoyIZT5fPlG44bPq50Wgh0INxykdrYX7&index=1">Hemanth.HM: The New gen of *gen(){}</a></li>
<li><a href="http://taskjs.org/">Task.js</a></li>
</ul>
</li>
</ul>
|