JavaScript迭代器与生成器之生成器

生成器Gengrator是ES6 新增的函数功能,它允许你定义一个包含自有迭代算法的函数,同时它可以自动维护自己的状态 。本文来总结一下JAVAScript 中生成器的相关知识点 。
一、什么是生成器
生成器是ES6新增的一个极为灵活的结构,拥有在一个函数块内暂停和恢复代码执行的能力 。这种新能力具有深远的影响,比如,使用生成器可以自定义迭代器和实现协程 。
生成器函数
生成器函数提供了一个强大的选择:它允许你定义一个包含自有迭代算法的函数,同时它可以自动维护自己的状态 。生成器函数使用 function* 语法编写
//生成器函数声明
function* generatorFn() {}
//生成器函数表达式
let generatorFn = function* () {};
//作为对象字面量方法的生成器函数
let foo = {
*generatorFn() {},
};
//作为类实例方法的生成器函数
class Foo {
*generatorFn() {}
}
//作为类静态方法的生成器函数
class Bar {
static *generatorFn() {}
}
//等价的生成器函数
function* generatorFnA() {}
function* generatorFnB() {}
function* generatorFnc() {}
//等价的生成器方法
class Foo {
*generatorFnD() {}
*generatorFnE() {}
}
注:箭头函数无法用来定义生成器函数

JavaScript迭代器与生成器之生成器

文章插图
生成器对象
调用生成器函数会产生一个生成器对象 。生成器对象一开始处于暂停执行(suspended)的状态 。与迭代器相似,生成器对象也实现了Iterator接口,因此具有next()方法 。调用这个方法会让生成器开始或恢复执行 。
function* generatorFn() {}
const gen = generatorFn();
console.log(gen); // generatorfn {<suspended>}
console.log(gen.next); // f next() {[native code]}
next()方法的返回值类似于迭代器,有一个done属性和一个value属性 。函数体为空的生成器函数中间不会停留,调用一次next()就会让生成器到达done:true状态 。
function* generatorFn() {}
const gen = generatorFn();
console.log(gen); // generatorfn {<suspended>}
console.log(gen.next()); //{value: undefined, done: true}
生成器函数只会在初次调用next()方法后开始执行,如下所示:
function* generatorFn() {
console.log("我执行了");
}
//初次调用生成器函数并不会打印日志
let gen = generatorFn();
gen.next(); // 我执行了
生成器对象实现了Iterable接口,它们默认的迭代器是自引用的:
function* generatorFn() {}
console.log(generatorFn); // f*generator(){}
console.log(generatorFn()[Symbol.iterator]);
// f[Symbol.iterator](){native code}
console.log(generatorFn());
// generatorFn{<suspended>}
console.log(generatorFn()[Symbol.iterator]());
// generatorFn{<suspended>}
const g = generatorFn();
console.log(g === g[Symbol.iterator]()); // true
二、yield关键字
生成器会在每个yield 语句后停止执行,在函数中停止执行的能力是极其强大的,yield 关键字指定了迭代器在被调用next的方法是应当按顺序返回的值,在没有调用next() 方法的时候,生成器函数里的的代码并不会执行,同时也可用通过return 返回生成器函数的返回值
function* generatorFn() {
console.log("start");
yield 1;
yield;
yield 2;
return 3;
}
let generatorObject = generatorFn();
console.log(generatorObject.next());
//start { value: 1, done: false}
console.log(generatorObject.next());
// { value: undefined, done: false }
console.log(generatorObject.next());
// { value: 2, done: false }
console.log(generatorObject.next());
// { value: 3, done: true }
此时的yield关键字有点像函数的中间返回语句,它生成的值会出现在next()方法返回的对象里 。通过yield关键字退出的生成器函数会处在done:false状态;通过return关键字退出的生成器函数会处于done:true状态 。
yield关键字详解
yield 关键字可以和值或者是表达式在一起使用,因此可以通过生成器给迭代器添加项目,而不是机械化地将项目一个个列出:
// for循环内部使用yield关键字
function* createIterator2(items) {
//let 块级作用域
for (let i = 0; i < items.length; i++) {
yield items[i];
}
}
let iterator2 = createIterator2([1, 2, 3]);
console.log(iterator2.next());
//{value:1, done:false}
console.log(iterator2.next());
//{value:2, done:false}
console.log(iterator2.next());


推荐阅读