第七章:迭代器与生成器
7.1 理解迭代
7.2 迭代器模式
7.2.1 可迭代协议
- 支持迭代的自我识别
- 创建实现 Iterator 接口的对象的能力
7.2.2 迭代器协议
next()
返回值:{ value: any, done: boolean }
- 不同迭代器的实例之间没有联系
- 对可迭代对象的修改会体现在迭代器上
class Test {
[Symbol.iterator]() {
return {
next() {
return { done: false, value: 'test' };
}
};
}
}
let t = new Test();
console.log(t[Symbol.iterator]());
7.2.3 自定义迭代器
- 任何实现了 Iterator 接口的对象都可以作为迭代器使用
class Counter {
constructor(limit) {
this.limit = limit;
}
[Symbol.iterator]() {
let count = 1;
let limit = this.limit;
return {
next() {
if (count <= limit) {
return { done: false, value: count++ };
}
else {
return { done: true, value: undefined };
}
}
};
}
}
let t = new Counter(3);
for (const child of t) {
console.log(child);
}
- 每个用这种方式创建的迭代器也实现了 Iterable 接口,会返回相同的迭代器(===)
let arr = [1, 2, 3, 4, 5];
let iter1 = arr[Symbol.iterator]();
let iter2 = iter1[Symbol.iterator]();
console.log(iter1 === iter2);
console.log(iter1.next());
console.log(iter2.next());
7.2.4 提前终止迭代器
return()
- 可选的
return()
方法提前关闭迭代器。未关闭的迭代器下次会继续从中断的地方迭代 - 并非所有迭代器都可以关闭
- 调用该方法不会强制迭代器进入关闭状态
7.3 生成器
7.3.1 生成器基础
- 箭头函数不能用来定义生成器函数
- 星号不受两侧空格影响
function * generatorFn1() {
}
let generatorFn2 = function* () {}
let foo = {
* generatorFn() {}
}
- 调用生成器函数会产生一个生成器对象
- 一开始处于暂停执行(suspended)状态
- 该对象也实现了 Iterator 接口,具有
next()
方法。调用该方法会让生成器开始或恢复执行 - 该对象实现了 Iterable 接口,默认的迭代器是自引用的
7.3.2 通过 yield 中断执行
yield
关键字可以让生成器停止或开始执行yield
不能位于嵌套的函数中
function* generatorFn() {
yield 'a';
yield 'b';
return 'c';
}
let generator = generatorFn();
console.log(generator.next());
console.log(generator.next());
console.log(generator.next());
1. 生成器对象作为可迭代对象
function* generatorFn() {
yield 'a';
yield 'b';
yield 'c';
}
for (const x of generatorFn()) {
console.log(x);
}
2. 使用 yield
实现输入和输出
3. 产生可迭代对象
- 使用
yield*
迭代一个可迭代对象。从而一次产生一个值
function* generatorFn() {
yield* [1, 2, 3];
}
for (const x of generatorFn()) {
console.log(x);
}
4. 使用 yield*
实现递归算法
function* generatorFn(n) {
if (n > 0) {
yield* generatorFn(n - 1);
yield n - 1;
}
}
for (const x of generatorFn(3)) {
console.log(x);
}
7.3.3 生成器作为默认迭代器
class Foo {
constructor() {
this.values = [1, 2, 3];
}
*[Symbol.iterator]() {
yield* this.values;
}
}
const f = new Foo();
for (const x of f) {
console.log(x);
}
7.3.4 提前终止生成器
1. return()
2. throw()
- 暂停的同时将提供的 error 注入生成器对象
- 未被处理会关闭生成器
- 内部进行了处理则会跳过对应的
yield
function* test() {
for (const x of [1, 2, 3]) {
try {
yield x;
}
catch (e) {
console.log(e);
}
}
}
const t = test();
console.log(t.next());
t.throw("foo");
console.log(t.next());