--- title: function* slug: Web/JavaScript/Reference/Statements/function* tags: - ECMAScript 2015 - Function - Iterator - JavaScript - Statement translation_of: Web/JavaScript/Reference/Statements/function* --- <div>{{jsSidebar("Statements")}}</div> <p><code><strong>function*</strong></code> 宣告式(<code>function</code> 關鍵字後面跟著一個星號)定義了一個<em>生成器函式(generator function)</em>,他會回傳一個{{jsxref("Global_Objects/Generator","生成器(Generator)")}}物件。</p> <div>{{EmbedInteractiveExample("pages/js/statement-functionasterisk.html")}}</div> <div class="noinclude"> <p>你可以透過 {{jsxref("GeneratorFunction")}} 建構式來定義生成器函式。</p> </div> <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> <dt><code>param</code></dt> <dd>要被傳入函式的引數名稱,一個函式最多可以擁有 255 個引數。</dd> <dt><code>statements</code></dt> <dd>statements 構成了函式內容的陳述式。</dd> </dl> <h2 id="描述">描述</h2> <p>生成器是可以離開後再次進入的函式。在兩次進入之間,生成器的執行狀態(變數綁定狀態)會被儲存。</p> <p>呼叫生成器函式並不會讓裡面的程式碼立即執行,而是會回傳一個針對該函式的<a href="/zh-TW/docs/Web/JavaScript/Reference/Iteration_protocols#iterator">迭代器(iterator)</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> 陳述式。</p> <p>生成器中的 <code>return</code> 陳述式被執行時,會讓生成器 <code>done</code> 狀態為真。若有數值被返回的動作帶回,將是放在 <code>value</code> 傳回的。已返回的生成器不會再產生任何數值。</p> <h2 id="範例">範例</h2> <h3 id="簡單例子">簡單例子</h3> <pre class="brush: js">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="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="傳入引數至生成器">傳入引數至生成器</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(); // the first call of next executes from the start of the function // until the first yield statement gen.next(); // 0 gen.next('pretzel'); // 1 pretzel gen.next('california'); // 2 california gen.next('mayonnaise'); // 3 mayonnaise </pre> <h3 id="生成器中的回傳陳述式">生成器中的回傳陳述式</h3> <pre class="brush: js">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="生成器無法被建構">生成器無法被建構</h3> <pre class="brush: js example-bad">function* f() {} var obj = new f; // throws "TypeError: f is not a constructor"</pre> <h3 id="以表達式定義生成器">以表達式定義生成器</h3> <pre><code>const foo = function* () { yield 10; yield 20; }; const bar = foo();console.log(bar.next()); // {value: 10, done: false}</code></pre> <p> </p> <h2 id="規範">規範</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', '#', 'function*')}}</td> <td>{{Spec2('ES2015')}}</td> <td>Initial definition.</td> </tr> <tr> <td>{{SpecName('ES2016', '#', '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', '#', '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="Generators_and_iterators_in_Firefox_versions_before_26">Generators and iterators in Firefox versions before 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="參見">參見</h2> <ul> <li>{{jsxref("Operators/function*", "function* expression")}}</li> <li>{{jsxref("GeneratorFunction")}} object</li> <li><a href="/zh-TW/docs/Web/JavaScript/Reference/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>Other web resources: <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://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>