这是我参与8月更文挑战的第3天,活动详情查看:8月更文挑战
生成器是ES6新出的一种特殊的函数,调用之后会返回一个生成器对象,它实现了Iterable接口,因此可以用在任何可迭代对象身上,生成器的独特之处就是支持yield,yield可以暂停执行的生成器函数,还可以通过next()方法接受输入和产生输出,在关键字加上 * 号后还可以将跟着它后面的可迭代对象序列化为一连串值。
在函数名称前加一个 * 号就表示它是一个生成器,只要是可以定义函数,就可以定义生成器
// 生成器函数声明
function* generatorFn() {}
// 生成器函数表达式
let generatorFn = function* () {}
// 作为对象字面量方法的生成器函数
let foo = {
* generatorFn() {}
}
// 作为类实例方法的生成器函数
class Foo {
* generatorFn() {}
}
// 作为类静态方法的生成器函数
class Bar {
static * generatorFn() {}
}
注意:箭头函数不能用来定义生成器
生成器一开始处于暂停执行的状态(suspended),生成器也实现了iterator接口,同样也可以调用next()方法,调用这个方法会让生成器开始或恢复执行
function * generatorFn(){};
const f = generatorFn();
console.log(f,f.next());
//generatorFn {<closed>} Window {value: undefined, done: true}
生成器在遇到yield关键字之前会正常执行,遇到这个关键字后会停止执行,函数的作用域状态会被保留,如果停止了还需要调用next()方法来恢复执行
function * generatorFn(){
yield;
};
const f = generatorFn();
console.log(f.next()); //{value: undefined, done: false}
console.log(f.next()); //{value: undefined, done: true}
yield生成的值会出现在next()方法里,通过yield退出的生成器函数会处在 done:false状态,通过retutn退出的生成器会处于 done :true状态
function * generatorFn(){
yield 'jackson';
return 'bear';
};
const f = generatorFn();
console.log(f.next()); //{value: "jackson", done: false}
console.log(f.next()); //{value: "bear", done: true}
yield 关键字的优先级很低,yield 之后的表达式基本上都要优先计算,只有 spread(展开运算符) 运算符和逗号运算符的优先级比它低。
因为生成器哦对象实现了Iterable接口,而且生成器和默认迭代器被调用之后都可以产生迭代器,所以生成器格外适合作为默认迭代器
class Foo {
constructor() {
this.values = ['jackson', 'bear'];
}
*[Symbol.iterator]() {
yield* this.values;
}
}
const f = new Foo();
for (const x of f) {
console.log(x);
}
// jackson
// bear
与迭代器不同,所有生成器对象都有return()方法,只要通过它进入关闭状态,就无法恢复了。 后续调用 next()会显示 done: true 状态,而提供的任何返回值都不会被存储或传播:
注意 如果生成器对象还没有开始执行,那么调用 throw()抛出的错误不会在函数内部被捕获,因为这相当于在函数块外部抛出了错误