何为生成器?
生成器(generator
)是能返回一个迭代器的函数。生成器函数由放在 function
关键字之后的一个星号(*
)来表示,并能使用新的 yield
关键字。将星号紧跟在 function
关键字之后,或是在中间留出空格,都是没问题的,正如下例:
// generator
function *createIterator() {
yield 1;
yield 2;
yield 3;
}
// generators are called like regular functions but return an iterator
let iterator = createIterator();
console.log(iterator.next().value); // 1
console.log(iterator.next().value); // 2
console.log(iterator.next().value); // 3
createIterator()
前面的星号让此函数变成一个生成器。yield
关键字也是 ES6
新增的,指定了迭代器在被 next()
方法调用时应当按顺序返回的值。此例所生成的迭代器能够在 next()
方法调用成功时返回三个不同的值:先是 1
,然后是 2
,最后则是 3
。生成器能像任意其他函数那样被调用,正如示例中创建 iterator
的代码。
生成器函数最有意思的方面可能就是它们会在每个 yield
语句后停止执行。例如,此代码中 yield 1
执行后,该函数将不会再执行任何操作,直到迭代器的 next()
方法被调用,此时才继续执行 yield 2
。在函数中停止执行的能力是极其强大的,并能引出生成器函数的一些有趣的用法(详见 “迭代器高级功能” 一节) 。
yield
关键字可以和值或是表达式一起使用,因此你可以通过生成器给迭代器添加项目,而不是机械化地将项目一个个列出。作为一个例子,此处给出了在 for
循环内使用 yield
的方法:
function *createIterator(items) {
for (let i = 0; i < items.length; i++) {
yield items[i];
}
}
let iterator = createIterator([1, 2, 3]);
console.log(iterator.next()); // "{ value: 1, done: false }"
console.log(iterator.next()); // "{ value: 2, done: false }"
console.log(iterator.next()); // "{ value: 3, done: false }"
console.log(iterator.next()); // "{ value: undefined, done: true }"
// for all further calls
console.log(iterator.next()); // "{ value: undefined, done: true }"
此例传递了一个名为 items
的数组给 createIterator()
生成器函数。在此函数内,for
循环在循环执行时从数组中返回元素给迭代器。每当遇到 yield,循环就会停止;而每当 iterator
上的 next()
方法被调用,循环就会再次执行到 yield
语句处。
生成器函数是 ES6
的一个重要特性,并且因为它就是函数,就能被用于所有可用函数的位置。本节剩余部分会集中于书写生成器的其他有用方法。
尽管 |
生成器函数表达式
你可以使用函数表达式来创建一个生成器,只要在 function
关键字与圆括号之间使用一个星号(*
)即可。例如:
let createIterator = function *(items) {
for (let i = 0; i < items.length; i++) {
yield items[i];
}
};
let iterator = createIterator([1, 2, 3]);
console.log(iterator.next()); // "{ value: 1, done: false }"
console.log(iterator.next()); // "{ value: 2, done: false }"
console.log(iterator.next()); // "{ value: 3, done: false }"
console.log(iterator.next()); // "{ value: undefined, done: true }"
// for all further calls
console.log(iterator.next()); // "{ value: undefined, done: true }"
此代码中的 createIterator()
是一个生成器函数表达式,而不是一个函数声明。星号放置在 function
关键字与圆括号之间,是因为这个函数表达式是匿名的。除此之外,此例与前一个版本的 createIterator()
函数没有区别,都使用了一个 for
循环。
不能将箭头函数创建为生成器。 |
生成器对象方法
由于生成器就是函数,因此也可以被添加到对象中。例如,你可以在 ES5
风格的对象字面量中使用函数表达式来创建一个生成器:
var o = {
createIterator: function *(items) {
for (let i = 0; i < items.length; i++) {
yield items[i];
}
}
};
let iterator = o.createIterator([1, 2, 3]);
你也可以使用 ES6
方法的速记法,只要在方法名之前加上一个星号(*
):
var o = {
*createIterator(items) {
for (let i = 0; i < items.length; i++) {
yield items[i];
}
}
};
let iterator = o.createIterator([1, 2, 3]);
这些例子的功能等价于 “生成器函数表达式” 小节中的例子,只是语法有区别。在速记法版本中,由于 createIterator()
方法没有使用 function
关键字来定义,星号就紧贴在方法名之前,不过其实你可以在星号与方法名之间留下空格。