function* 这种声明方式(function关键字后跟一个星号)会定义一个生成器函数 (generator function),它返回一个  Generator  对象。

你也可以使用构造函数  GeneratorFunctionfunction* expression 定义生成器函数

语法

function* name([param[, param[, ... param]]]) { statements }
name
函数名
param
要传递给函数的一个参数的名称,一个函数最多可以有255个参数。
statements
普通JS语句。

描述

生成器函数在执行时能暂停,后面又能从暂停处继续执行。

调用一个生成器函数并不会马上执行它里面的语句,而是返回一个这个生成器的 迭代器 (iterator )对象。当这个迭代器的 next() 方法被首次(后续)调用时,其内的语句会执行到第一个(后续)出现yield的位置为止,yield 后紧跟迭代器要返回的值。或者如果用的是 yield*(多了个星号),则表示将执行权移交给另一个生成器函数(当前生成器暂停执行)。

next()方法返回一个对象,这个对象包含两个属性:value 和 done,value 属性表示本次 yield 表达式的返回值,done 属性为布尔类型,表示生成器后续是否还有 yield 语句,即生成器函数是否已经执行完毕并返回。

调用 next()方法时,如果传入了参数,那么这个参数会作为上一条执行的  yield 语句的返回值,例如:

function *gen(){
    yield 10;
    y=yield 'foo';
    yield y;
}

var gen_obj=gen();
console.log(gen_obj.next());// 执行 yield 10,返回 10
console.log(gen_obj.next());// 执行 yield 'foo',返回 'foo'
console.log(gen_obj.next(10));// 将 10 赋给上一条 yield 'foo' 的左值,即执行 y=10,返回 10
console.log(gen_obj.next());// 执行完毕,value 为 undefined,done 为 true

当在生成器函数中显式 return 时,会导致生成器立即变为完成状态,即调用 next() 方法返回的对象的 done true。如果 return 后面跟了一个值,那么这个值会作为当前调用 next() 方法返回的 value 值。

示例

简单示例

function* idMaker(){
  var index = 0;
  while(index<3)
    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); // undefined

生成器也可以接收参数:

function* idMaker(){
    var index = arguments[0] || 0;
    while(true)
        yield index++;
}

var gen = idMaker(5);
console.log(gen.next().value); // 5
console.log(gen.next().value); // 6

yield*的示例

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

传递参数

function *createIterator() {
    let first = yield 1;
    let second = yield first + 2; // 4 + 2 
                                  // first =4 是next(4)将参数赋给上一条的
    yield second + 3;             // 5 + 3
}

let iterator = createIterator();

console.log(iterator.next());    // "{ value: 1, done: false }"
console.log(iterator.next(4));   // "{ value: 6, done: false }"
console.log(iterator.next(5));   // "{ value: 8, done: false }"
console.log(iterator.next());    // "{ value: undefined, done: true }"

显式返回

function* yieldAndReturn() {
  yield "Y";
  return "R";//显式返回处,可以观察到 done 也立即变为了 true
  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 }

生成器函数不能当构造器使用

function* f() {}
var obj = new f; // throws "TypeError: f is not a constructor"

使用迭代器遍历二维数组并转换成一维数组:

function* iterArr(arr) {            //迭代器返回一个迭代器对象
  if (Array.isArray(arr)) {         // 内节点
      for(let i=0; i < arr.length; i++) {
          yield* iterArr(arr[i]);   // (*)递归
      }
  } else {                          // 离开     
      yield arr;
  }
}
// 使用 for-of 遍历:
var arr = ['a', ['b', 'c'], ['d', 'e']];
for(var x of iterArr(arr)) {
        console.log(x);               // a  b  c  d  e
 }

// 或者直接将迭代器展开:
var arr = [ 'a', ['b',[ 'c', ['d', 'e']]]];
var gen = iterArr(arr);
arr = [...gen];                        // ["a", "b", "c", "d", "e"]

规范

Specification Status Comment
ECMAScript 2015 (6th Edition, ECMA-262)
function*
Standard Initial definition.
ECMAScript Latest Draft (ECMA-262)
function*
Draft  

浏览器兼容性

Update compatibility data on GitHub
DesktopMobileServer
ChromeEdgeFirefoxInternet ExplorerOperaSafariAndroid webviewChrome for AndroidEdge MobileFirefox for AndroidOpera for AndroidSafari on iOSSamsung InternetNode.js
function*Chrome Full support 39Edge Full support 13Firefox Full support 26IE No support NoOpera Full support 26Safari Full support 10WebView Android Full support YesChrome Android Full support 39Edge Mobile Full support YesFirefox Android Full support 26Opera Android Full support YesSafari iOS Full support 10Samsung Internet Android Full support 4.0nodejs Full support 4.0.0
Full support 4.0.0
Full support 0.12
Disabled
Disabled From version 0.12: this feature is behind the --harmony runtime flag.
IteratorResult object instead of throwingChrome Full support 49Edge Full support 13Firefox Full support 29IE No support NoOpera Full support YesSafari Full support YesWebView Android Full support YesChrome Android Full support YesEdge Mobile Full support YesFirefox Android Full support 29Opera Android Full support YesSafari iOS Full support YesSamsung Internet Android Full support Yesnodejs Full support Yes
Not constructable with new (ES2016)Chrome Full support YesEdge ? Firefox Full support 43IE No support NoOpera Full support YesSafari Full support 10WebView Android Full support YesChrome Android Full support YesEdge Mobile ? Firefox Android Full support 43Opera Android Full support YesSafari iOS Full support 10Samsung Internet Android Full support Yesnodejs Full support Yes
Trailing comma in parametersChrome ? Edge ? Firefox Full support 52IE No support NoOpera Full support YesSafari ? WebView Android ? Chrome Android ? Edge Mobile ? Firefox Android Full support 52Opera Android ? Safari iOS ? Samsung Internet Android ? nodejs Full support 8.0.0

Legend

Full support  
Full support
No support  
No support
Compatibility unknown  
Compatibility unknown
User must explicitly enable this feature.
User must explicitly enable this feature.
 

Firefox浏览器具体事项

Firefox 26之前的生成器和迭代器

旧版本的Firefox实施了旧版本的生成器提案。旧版中用普通的function关键字定义(没有星号).

IteratorResult不再抛出错误

从Gecko 29 (Firefox 29 / Thunderbird 29 / SeaMonkey 2.26)开始,完成的生成器函数不再抛出TypeError "generator has already finished". 而是返回一个IteratorResult对象:{ value: undefined, done: true } (bug 958951)。

相关链接