function*
function*
声明将新的生成器函数的绑定到给定名称。生成器函数可以退出,并在以后重新进入,其上下文(变量绑定)在重新进入之间保存。
您还可以使用function*
表达式定义生成器函数。
试一试
语法
function* name(param0) {
statements
}
function* name(param0, param1) {
statements
}
function* name(param0, param1, /* …, */ paramN) {
statements
}
注意:生成器函数没有箭头函数的对应项。
注意:function
和 *
是单独的标记,因此它们可以用空格或换行符分隔。
参数
名称
-
函数名称。
param
可选-
函数的形式参数的名称。有关参数的语法,请参阅函数参考。
statements
可选-
构成函数体的语句。
描述
function*
声明创建一个GeneratorFunction
对象。每次调用生成器函数时,它都会返回一个新的Generator
对象,该对象符合迭代器协议。当调用迭代器的 next()
方法时,生成器函数的主体将执行到第一个yield
表达式,该表达式指定要从迭代器返回的值,或者使用yield*
委托给另一个生成器函数。next()
方法返回一个对象,该对象具有一个包含已生成值的 value
属性和一个指示生成器是否已生成其最后一个值的 done
属性(作为布尔值)。使用参数调用 next()
方法将恢复生成器函数的执行,将执行暂停处的 yield
表达式替换为 next()
中的参数。
JavaScript 中的生成器——尤其是在与 Promise 结合使用时——是用于异步编程的非常强大的工具,因为它们可以减轻——如果不是完全消除——回调带来的问题,例如回调地狱和控制反转。但是,可以使用异步函数更简单地解决这些问题。
生成器中的 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();
// 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
生成器中的 return 语句
function* yieldAndReturn() {
yield "Y";
return "R";
yield "unreachable";
}
const 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 }
作为对象属性的生成器
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) {
//endless loop to generate
for (let current = n; ; current *= n) {
yield current;
}
}
for (const power of powers(2)) {
// controlling generator
if (power > 32) {
break;
}
console.log(power);
// 2
// 4
// 8
// 16
// 32
}
规范
规范 |
---|
ECMAScript 语言规范 # sec-generator-function-definitions |
浏览器兼容性
BCD 表格仅在浏览器中加载
另请参阅
- 函数 指南
- 迭代器和生成器 指南
- 函数
GeneratorFunction
function*
表达式function
异步函数
异步函数*
- 迭代协议
yield
yield*
Generator
- Regenerator 在 GitHub 上
- Promises 和生成器:控制流乌托邦 Forbes Lindesay 在 JSConf(2013)上的演示
- Task.js 在 GitHub 上
- You Don't Know JS:异步和性能,第 4 章:生成器 作者:Kyle Simpson