function*
Baseline Widely available
This feature is well established and works across many devices and browser versions. It’s been available across browsers since September 2016.
function*
声明创建一个绑定到给定名称的新生成器函数。生成器函数可以退出,并在稍后重新进入,其上下文(变量绑定)会在重新进入时保存。
你也可以使用 function*
表达式来定义生成器函数。
尝试一下
语法
function* name(param0) {
statements
}
function* name(param0, param1) {
statements
}
function* name(param0, param1, /* …, */ paramN) {
statements
}
备注: 箭头函数不能用来定义生成器函数。
备注: function
和 *
是两个单独的标记,因此它们可以用空白或换行符分隔。
参数
name
-
函数名称。
param
可选-
函数的形参名称。有关参数的语法,请参阅函数参考。
statements
可选-
构成函数体的语句。
描述
function*
声明创建一个 GeneratorFunction
对象。每次调用生成器函数时,它都会返回一个新的 Generator
对象,该对象符合迭代器协议。当迭代器的 next()
方法被调用时,生成器函数的主体会被执行,直到遇到第一个 yield
表达式,该表达式指定了迭代器要返回的值,或者用 yield*
委托给另一个生成器函数。next()
方法返回一个对象,其 value
属性包含了 yield
表达式的值,done
属性是布尔类型,表示生成器是否已经返回了最后一个值。如果 next()
方法带有参数,那么它会恢复生成器函数的执行,并用参数替换暂停执行的 yield
表达式。
在 JavaScript 中,生成器——尤其是与 Promises 结合使用时——是一种非常强大的异步编程工具,它们解决了回调函数存在的一些的问题,如回调地狱和控制反转。然而,通过使用异步函数,我们可以更简单地解决这些问题。
在生成器中执行 return
语句会使生成器结束(即返回的对象的 done
属性将被设置为 true
)。如果返回一个值,它将被设置为生成器返回的对象的 value
属性。与 return
语句类似,如果生成器内部抛出错误,生成器也会结束,除非在生成器的代码体内捕获该错误。当生成器结束后,后续 next()
调用不会执行生成器的任何代码,只会返回一个形如 {value: undefined, done: true}
的对象。
function*
声明的行为与 function
声明类似——它们会被提升到其作用域的顶部,并且可以在当前作用域的任何位置被调用,且只能在特定的上下文中被重新声明。
示例
简单示例
function* idMaker() {
let index = 0;
while (true) {
yield index++;
}
}
const 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
// …
使用 yield* 示例
function* anotherGenerator(i) {
yield i + 1;
yield i + 2;
yield i + 3;
}
function* generator(i) {
yield i;
yield* anotherGenerator(i);
yield i + 10;
}
const 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* logGenerator() {
console.log(0);
console.log(1, yield);
console.log(2, yield);
console.log(3, yield);
}
const gen = logGenerator();
// next 的第一次调用从函数的开头开始执行,直到第一个 yield 语句
gen.next(); // 0
gen.next("pretzel"); // 1 pretzel
gen.next("california"); // 2 california
gen.next("mayonnaise"); // 3 mayonnaise
生成器中的返回语句
function* yieldAndReturn() {
yield "产生的值";
return "返回的值";
yield "不会被访问到的值";
}
const gen = yieldAndReturn();
console.log(gen.next()); // { value: "产生的值", done: false }
console.log(gen.next()); // { value: "返回的值", done: true }
console.log(gen.next()); // { value: undefined, done: true }
生成器作为对象属性
const someObj = {
*generator() {
yield "a";
yield "b";
},
};
const gen = someObj.generator();
console.log(gen.next()); // { value: 'a', done: false }
console.log(gen.next()); // { value: 'b', done: false }
console.log(gen.next()); // { value: undefined, done: true }
生成器作为对象方法
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 }
生成器作为计算属性
class Foo {
*[Symbol.iterator]() {
yield 1;
yield 2;
}
}
const SomeObj = {
*[Symbol.iterator]() {
yield "a";
yield "b";
},
};
console.log(Array.from(new Foo())); // [ 1, 2 ]
console.log(Array.from(SomeObj)); // [ 'a', 'b' ]
生成器是不可构造的
function* f() {}
const obj = new f(); // throws "TypeError: f is not a constructor
使用表达式定义生成器
const foo = function* () {
yield 10;
yield 20;
};
const bar = foo();
console.log(bar.next()); // {value: 10, done: false}
生成器示例
function* powers(n) {
// 无限循环生成
for (let current = n; ; current *= n) {
yield current;
}
}
for (const power of powers(2)) {
// 控制生成器
if (power > 32) {
break;
}
console.log(power);
// 2
// 4
// 8
// 16
// 32
}
规范
Specification |
---|
ECMAScript Language Specification # sec-generator-function-definitions |
浏览器兼容性
BCD tables only load in the browser
参见
- 函数指南
- 迭代器与生成器指南
- 函数
GeneratorFunction
function*
表达式function
async function
async function*
- 迭代协议
yield
yield*
Generator
- GitHub 上的 Regenerator
- Promise 和生成器:控制流的乌托邦——Forbes Lindesay 在 JSConf 上的演讲(2013)
- GitHub 上的 Task.js
- 你不知道的 JS:异步和性能,第 4 章:生成器——Kyle Simpson