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
|
---
title: function*
slug: Web/JavaScript/Reference/Statements/function*
translation_of: Web/JavaScript/Reference/Statements/function*
---
<div>{{jsSidebar("Statements")}}</div>
<p>Khai báo <code><strong>function*</strong></code> (từ khóa <code>function</code> tiếp theo là dấu sao) định nghĩa một <em>generator function</em>, một phương thức trả về đối tượng {{jsxref("Global_Objects/Generator","Generator")}}.</p>
<div>{{EmbedInteractiveExample("pages/js/statement-functionasterisk.html")}}</div>
<div class="noinclude">
<p>Bạn cũng có thể khai báo generator functions bằng constructor {{jsxref("GeneratorFunction")}} , hoặc cú pháp function expression.</p>
</div>
<h2 id="Cú_pháp">Cú pháp</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>Tên phương thức</dd>
</dl>
<dl>
<dt><code>param</code></dt>
<dd>Các tham số truyền vào cho phương thức.</dd>
</dl>
<dl>
<dt><code>statements</code></dt>
<dd>Các câu lệnh bên trong phương thức</dd>
</dl>
<h2 id="Diễn_giải">Diễn giải</h2>
<p>Generators là một hàm có thể thoát và sau đó gọi lại lần nữa. Giá trị của biến trong các lần gọi được lưu lại trong các lần gọi tiếp theo.<br>
<br>
Pattern là cách hàm <code><a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function">async</a></code> được viết ra.</p>
<p>Gọi một generator function không thực thi các lệnh bên trong hàm ngày lập tức; Thay vào đó, một object <a href="/en-US/docs/Web/JavaScript/Reference/Iteration_protocols#iterator">iterator</a> được trả về. Khi iterator gọi đến phương thức <code>next()</code> , lúc này các lệnh bên trong hàm được thực thi cho đến khi gặp câu {{jsxref("Operators/yield", "yield")}} , sau câu lệnh {{jsxref("Operators/yield", "yield")}} là giá trị sẽ trả về, hoặc gọi đến một generator function khác. Phương thức <code>next()</code> trả về một object với property <code>value</code> chứa giá trị yielded và property <code>done</code> , giá trị kiểu boolean, xác định generator yielded trả về đã là cuối cùng chưa. Gọi phương thức <code>next()</code> với một tham số sẽ chạy hàm generator tiếp tục, thay thế câu <code>yield</code> nơi hàm đã dừng lại trước đó với tham số từ <code>next()</code>. </p>
<p>Câu lệnh <code>return</code> trong generator, khi chạy, sẽ kết thúc generator (ví dụ property <code>done</code> trả về sẽ có giá trị <code>true</code>). Nếu giá trị đã được trả về, nó sẽ được set cho property <code>value</code>.<br>
Giống như câu lệnh <code>return</code> , thrown error trong generator sẽ kết thúc generator -- trừ khi bắt lại bằng bên trong generator.<br>
Khi một generator kết thúc, các câu gọi <code>next</code> tiếp theo sau sẽ không được thực thi, nó chỉ trả về object có dạng: <code>{value: undefined, done: true}</code>.</p>
<h2 id="Ví_dụ">Ví dụ</h2>
<h3 id="Ví_dụ_đơn_giản">Ví dụ đơn giản</h3>
<pre class="brush: js notranslate">function* idMaker() {
var index = 0;
while (index < index+1)
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="Ví_dụ_với_yield*">Ví dụ với yield*</h3>
<pre class="brush: js notranslate">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="Truyền_tham_số_vào_trong_Generators">Truyền tham số vào trong Generators</h3>
<pre class="brush: js notranslate">function* logGenerator() {
console.log(0);
console.log(1, yield);
console.log(2, yield);
console.log(3, yield);
}
var gen = logGenerator();
gen.next(); // 0
gen.next('pretzel'); // 1 pretzel
gen.next('california'); // 2 california
gen.next('mayonnaise'); // 3 mayonnaise
</pre>
<h3 id="Return_bên_trong_generator">Return bên trong generator</h3>
<pre class="brush: js notranslate">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 }
</pre>
<h3 id="Generators_không_dùng_constructable">Generators không dùng constructable</h3>
<pre class="brush: js notranslate">function* f() {}
var obj = new f; // throws "TypeError: f is not a constructor
</pre>
<h3 id="Generator_khai_báo_bằng_expression">Generator khai báo bằng expression</h3>
<pre class="brush: js notranslate">const foo = function* () {
yield 10;
yield 20;
};
const bar = foo();
console.log(bar.next()); // {value: 10, done: false}</pre>
<h2 id="Specifications">Specifications</h2>
<table class="standard-table">
<thead>
<tr>
<th scope="col">Specification</th>
<th scope="col">Status</th>
<th scope="col">Comment</th>
</tr>
</thead>
<tbody>
<tr>
<td>{{SpecName('ES2015', '#sec-generator-function-definitions', 'function*')}}</td>
<td>{{Spec2('ES2015')}}</td>
<td>Initial definition.</td>
</tr>
<tr>
<td>{{SpecName('ES2016', '#sec-generator-function-definitions', 'function*')}}</td>
<td>{{Spec2('ES2016')}}</td>
<td>Changed that generators should not have [[Construct]] trap and will throw when used with <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="Trình_duyệt_hỗ_trợ">Trình duyệt hỗ trợ</h2>
<div>
<p>{{Compat("javascript.statements.generator_function")}}</p>
</div>
<h2 id="Lưu_ý_dành_riêng_cho_Firefox">Lưu ý dành riêng cho Firefox</h2>
<h4 id="Generators_và_iterators_trước_phiên_bản_Firefox_26">Generators và iterators trước phiên bản Firefox 26</h4>
<p>Older Firefox versions implement an older version of the generators proposal. In the older version, generators were defined using a regular <code>function</code> keyword (without an asterisk) among other differences. See <a href="/en-US/docs/Web/JavaScript/Reference/Statements/Legacy_generator_function">Legacy generator function </a>for further information.</p>
<h4 id="IteratorResult_object_returned_instead_of_throwing"><code>IteratorResult</code> object returned instead of throwing</h4>
<p>Starting with Gecko 29 {{geckoRelease(29)}}, the completed generator function no longer throws a {{jsxref("TypeError")}} "generator has already finished". Instead, it returns an <code>IteratorResult</code> object like <code>{ value: undefined, done: true }</code> ({{bug(958951)}}).</p>
<h2 id="Xem_thêm">Xem thêm</h2>
<ul>
<li>{{jsxref("Operators/function*", "function* expression")}}</li>
<li>{{jsxref("GeneratorFunction")}} object</li>
<li><a href="/en-US/docs/Web/JavaScript/Reference/Iteration_protocols">Iteration protocols</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>Nguồn trang khác:
<ul>
<li><a href="http://facebook.github.io/regenerator/">Regenerator</a> an ES2015 generator compiler to 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="https://github.com/mozilla/task.js">Task.js</a></li>
<li><a href="https://github.com/getify/You-Dont-Know-JS/blob/master/async%20%26%20performance/ch4.md#iterating-generators-asynchronously">Iterating generators asynchronously</a></li>
</ul>
</li>
</ul>
|