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
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
|
---
title: function*
slug: Web/JavaScript/Reference/Statements/function*
tags:
- ECMAScript 2015
- Function
- JavaScript
- Ітератор
- генератор
translation_of: Web/JavaScript/Reference/Statements/function*
---
<div>{{jsSidebar("Statements")}}</div>
<p>Оголошення <code><strong>function*</strong></code> (ключове слово <code>function</code> з зірочкою) визначає <em>функцію-генератор</em>, яка повертає об'єкт {{jsxref("Global_Objects/Generator","Generator")}}.</p>
<div>{{EmbedInteractiveExample("pages/js/statement-functionasterisk.html")}}</div>
<p>Ви також можете визначати функції-генератори за допомогою конструктора {{jsxref("GeneratorFunction")}} або функціонального виразу.</p>
<h2 id="Синтаксис">Синтаксис</h2>
<pre class="syntaxbox">function* <em>name</em>([<em>param</em>[, <em>param</em>[, ... <em>param</em>]]]) {
<em>statements</em>
}
</pre>
<dl>
<dt><code>name</code></dt>
<dd>Ім'я функції.</dd>
</dl>
<dl>
<dt><code>param</code></dt>
<dd>Ім'я формального параметра функції.</dd>
</dl>
<dl>
<dt><code>statements</code></dt>
<dd>Інструкції, що складають тіло функції.</dd>
</dl>
<h2 id="Опис">Опис</h2>
<p>Генератори - це функції, з яких можна вийти та пізніше повторно зайти. Їхній контекст (зв'язування змінних) збережеться між заходами.<br>
<br>
Генератори у JavaScript -- особливо у поєднанні з промісами -- дуже потужний інструмент асинхронного програмування, бо вони пом'якшують -- якщо не усувають повністю -- проблеми зворотних викликів, такі як <a href="http://callbackhell.com/">Пекло зворотних викликів</a> та <a href="https://frontendmasters.com/courses/rethinking-async-js/callback-problems-inversion-of-control/">Інверсія управління</a>.</p>
<p>Виклик функції-генератора не виконує тіло функції негайно; замість цього повертається об'єкт-<a href="/uk/docs/Web/JavaScript/Reference/Протоколи_перебору#Протокол_ітератора">ітератор</a> для функції. Коли викликається метод ітератора <code>next()</code>, тіло функції-генератора виконується до першого виразу {{jsxref("Operators/yield", "yield")}}, який визначає значення, що має бути повернене ітератором, або, оператором {{jsxref("Operators/yield*", "yield*")}}, делегується до іншої функції-генератора. Метод <code>next()</code> повертає об'єкт з властивістю <code>value</code>, що містить отримане значення, та властивістю <code>done</code>, яка вказує, чи генератор віддав останнє значення, у вигляді булевого значення. Виклик метода <code>next()</code> з аргументом відновить виконання функції-генератора, замінюючи вираз <code>yield</code> в тій точці, де виконання було призупинене, аргументом з <code>next()</code>.</p>
<p>Оператор <code>return</code> у генераторі змусить генератор завершити виконання (тобто, властивості <code>done</code> поверненого об'єкта буде присвоєне значення <code>true</code>). Якщо повертається значення, воно буде присвоєте властивості <code>value</code> об'єкта, що повертається генератором.<br>
Схоже на оператор <code>return</code>, викидання помилки всередині генератора змусить генератор завершити виконання -- якщо не буде перехоплене у тілі генератора.<br>
Коли генератор завершує виконання, наступні виклики <code>next</code> не виконають жодного коду генератора, вони лише повернуть об'єкт наступного вигляду: <code>{value: undefined, done: true}</code>.</p>
<h2 id="Приклади">Приклади</h2>
<h3 id="Простий_приклад">Простий приклад</h3>
<pre class="brush: js">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
console.log(gen.next().value); // 3
// ...</pre>
<h3 id="Приклад_з_yield*">Приклад з yield*</h3>
<pre class="brush: js">function* anotherGenerator(i) {
yield i + 1;
yield i + 2;
yield i + 3;
}
function* generator(i) {
yield i;
yield* anotherGenerator(i);
yield i + 10;
}
var gen = generator(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="Передача_аргументів_у_обєкти_Generator">Передача аргументів у об'єкти Generator</h3>
<pre class="brush: js">function* logGenerator() {
console.log(0);
console.log(1, yield);
console.log(2, yield);
console.log(3, yield);
}
var gen = logGenerator();
// перший виклик метода next виконує функцію з початку
// до першого оператора yield
gen.next(); // 0
gen.next('крендель'); // 1 крендель
gen.next('кава'); // 2 кава
gen.next('майонез'); // 3 майонез
</pre>
<h3 id="Оператор_return_у_генераторі">Оператор return у генераторі</h3>
<pre class="brush: js">function* yieldAndReturn() {
yield "Y";
return "R";
yield "недосяжний";
}
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 }
</pre>
<h3 id="Генератор_як_властивість_обєкта">Генератор як властивість об'єкта</h3>
<pre class="brush: js">const someObj = {
*generator () {
yield 'а';
yield 'б';
}
}
const gen = someObj.generator()
console.log(gen.next()); // { value: 'а', done: false }
console.log(gen.next()); // { value: 'б', done: false }
console.log(gen.next()); // { value: undefined, done: true }
</pre>
<h3 id="Генератор_як_метод_класу">Генератор як метод класу</h3>
<pre class="brush: js">class Foo {
*generator () {
yield 1;
yield 2;
yield 3;
}
}
const f = new Foo ();
const gen = f.generator();
console.log(gen.next()); // { value: 1, done: false }
console.log(gen.next()); // { value: 2, done: false }
console.log(gen.next()); // { value: 3, done: false }
console.log(gen.next()); // { value: undefined, done: true }
</pre>
<h3 id="Генератор_як_обчислювана_властивість">Генератор як обчислювана властивість</h3>
<pre class="brush: js">class Foo {
*[Symbol.iterator] () {
yield 1;
yield 2;
}
}
const SomeObj = {
*[Symbol.iterator] () {
yield 'а';
yield 'б';
}
}
console.log(Array.from(new Foo)); // [ 1, 2 ]
console.log(Array.from(SomeObj)); // [ 'а', 'б' ]
</pre>
<h3 id="Генератори_не_є_конструкторами">Генератори не є конструкторами</h3>
<pre class="brush: js">function* f() {}
var obj = new f; // викидає "TypeError: f is not a constructor
</pre>
<h3 id="Генератор_визначений_у_виразі">Генератор, визначений у виразі</h3>
<pre class="brush: js">const foo = function* () {
yield 10;
yield 20;
};
const bar = foo();
console.log(bar.next()); // {value: 10, done: false}</pre>
<h2 id="Специфікації">Специфікації</h2>
<table class="standard-table">
<thead>
<tr>
<th scope="col">Специфікація</th>
<th scope="col">Статус</th>
<th scope="col">Коментар</th>
</tr>
</thead>
<tbody>
<tr>
<td>{{SpecName('ES2015', '#sec-generator-function-definitions', 'function*')}}</td>
<td>{{Spec2('ES2015')}}</td>
<td>Початкове визначення.</td>
</tr>
<tr>
<td>{{SpecName('ES2016', '#sec-generator-function-definitions', 'function*')}}</td>
<td>{{Spec2('ES2016')}}</td>
<td>Внесено зміни, що генератори не повинні мати пастки [[Construct]] та викидатимуть помилку при використанні з <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="Сумісність_з_веб-переглядачами">Сумісність з веб-переглядачами</h2>
<div>
<p>{{Compat("javascript.statements.generator_function")}}</p>
</div>
<h2 id="Примітки_щодо_Firefox">Примітки щодо Firefox</h2>
<h4 id="Генератори_та_ітератори_у_Firefox_до_26-ї_версії">Генератори та ітератори у Firefox до 26-ї версії</h4>
<p>Старші версії Firefox реалізують старшу версію пропозиції генераторів. У старшій версії генератори визначались за допомогою звичайного ключового слова <code>function</code> (без зірочки), серед інших відмінностей. Дивіться більше інформації у статті <a href="/uk/docs/Web/JavaScript/Reference/Statements/Legacy_generator_function">Застаріла функція-генератор</a>.</p>
<h4 id="Замість_викидання_помилки_повертається_обєкт_IteratorResult">Замість викидання помилки повертається об'єкт <code>IteratorResult</code></h4>
<p>Починаючи з Gecko 29 {{geckoRelease(29)}}, завершена функція-генератор більше не викидає помилку {{jsxref("TypeError")}} "generator has already finished". Замість цього, вона повертає об'єкт <code>IteratorResult</code> у вигляді <code>{ value: undefined, done: true }</code> ({{bug(958951)}}).</p>
<h2 id="Див._також">Див. також</h2>
<ul>
<li>{{jsxref("Operators/function*", "вираз function*")}}</li>
<li>Об'єкт {{jsxref("GeneratorFunction")}}</li>
<li><a href="/uk/docs/Web/JavaScript/Reference/Протоколи_перебору">Протоколи перебору</a></li>
<li>{{jsxref("Operators/yield", "yield")}}</li>
<li>{{jsxref("Operators/yield*", "yield*")}}</li>
<li>Об'єкт {{jsxref("Function")}}</li>
<li>{{jsxref("Statements/function", "оголошення функції")}}</li>
<li>{{jsxref("Operators/function", "функціональний вираз")}}</li>
<li>{{jsxref("Functions", "Функції")}}</li>
<li>Інші веб-ресурси:
<ul>
<li><a href="http://facebook.github.io/regenerator/">Regenerator</a>, компілятор генераторів ES2015 у 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://github.com/mozilla/task.js">Task.js</a></li>
<li><a href="https://github.com/getify/You-Dont-Know-JS/blob/1st-ed/async%20%26%20performance/ch4.md#iterating-generators-asynchronously">Асинхронний перебір генераторів</a></li>
</ul>
</li>
</ul>
|