
2025-01-09 日报 Day61

今日的鸡汤
只有付出比别人更多的努力和功夫,你才能在一次次磨砺中,变得闪闪发光。
今日学习内容
1、JS 红皮书 P201-204 第七章:迭代器与生成器
今日笔记
1、生成器作为默认迭代器: 因为生成器对象实现了 Iterable 接口,而且生成器函数和默认迭代器被调用之后都产生迭代器,所以生成器格外适合作为默认迭代器。下面是一个简单的例子,这个类的默认迭代器可以用一行代码产出类的内容:
1 | class Foo { |
2、提前终止生成器: 与迭代器类似,生成器也支持“可关闭”的概念。一个实现 Iterator 接口的对象一定有 next()方法,还有一个可选的 return()方法用于提前终止迭代器。生成器对象除了有这两个方法,还有第三个方法:throw()。
1 | function* generatorFn() {} |
- return(): return()方法会强制生成器进入关闭状态。提供给 return()方法的值,就是终止迭代器对象的值:与迭代器不同,所有生成器对象都有 return()方法,只要通过它进入关闭状态,就无法恢复了。后续调用 next()会显示 done: true 状态,而提供的任何返回值都不会被存储或传播:
1
2
3
4
5
6
7
8
9function* generatorFn() {
for (const x of [1, 2, 3]) {
yield x;
}
}
const g = generatorFn();
console.log(g); // generatorFn {<suspended>}
console.log(g.return(4)); // { done: true, value: 4 }
console.log(g); // generatorFn {<closed>}1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26function* generatorFn() {
for (const x of [1, 2, 3]) {
yield x;
}
}
const g = generatorFn();
console.log(g.next()); // { done: false, value: 1 }
console.log(g.return(4)); // { done: true, value: 4 }
console.log(g.next()); // { done: true, value: undefined }
console.log(g.next()); // { done: true, value: undefined }
console.log(g.next()); // { done: true, value: undefined }
// for-of 循环等内置语言结构会忽略状态为 done: true 的 IteratorObject 内部返回的值。
function* generatorFn() {
for (const x of [1, 2, 3]) {
yield x;
}
}
const g = generatorFn();
for (const x of g) {
if (x > 1) {
g.return(4);
}
console.log(x);
}
// 1
// 2 - throw(): throw()方法会在暂停的时候将一个提供的错误注入到生成器对象中。如果错误未被处理,生成器就会关闭:不过,假如生成器函数内部处理了这个错误,那么生成器就不会关闭,而且还可以恢复执行。错误处理会跳过对应的 yield,因此在这个例子中会跳过一个值。比如:
1
2
3
4
5
6
7
8
9
10
11
12
13function* generatorFn() {
for (const x of [1, 2, 3]) {
yield x;
}
}
const g = generatorFn();
console.log(g); // generatorFn {<suspended>}
try {
g.throw('foo');
} catch (e) {
console.log(e); // foo
}
console.log(g); // generatorFn {<closed>}3、小结: ECMAScript 6 正式支持迭代模式并引入了两个新的语言特性:迭代器和生成器。1
2
3
4
5
6
7
8
9
10
11function* generatorFn() {
for (const x of [1, 2, 3]) {
try {
yield x;
} catch(e) {}
}
}
const g = generatorFn();
console.log(g.next()); // { done: false, value: 1}
g.throw('foo');
console.log(g.next()); // { done: false, value: 3}
迭代器是一个可以由任意对象实现的接口,支持连续获取对象产出的每一个值。任何实现 Iterable接口的对象都有一个 Symbol.iterator 属性,这个属性引用默认迭代器。默认迭代器就像一个迭代器工厂,也就是一个函数,调用之后会产生一个实现 Iterator 接口的对象。
迭代器必须通过连续调用 next()方法才能连续取得值,这个方法返回一个 IteratorObject。这个对象包含一个 done 属性和一个 value 属性。前者是一个布尔值,表示是否还有更多值可以访问;后者包含迭代器返回的当前值。这个接口可以通过手动反复调用 next()方法来消费,也可以通过原生消费者,比如 for-of 循环来自动消费。
生成器是一种特殊的函数,调用之后会返回一个生成器对象。生成器对象实现了 Iterable 接口,因此可用在任何消费可迭代对象的地方。生成器的独特之处在于支持 yield 关键字,这个关键字能够暂停执行生成器函数。使用 yield 关键字还可以通过 next()方法接收输入和产生输出。在加上星号之后,yield 关键字可以将跟在它后面的可迭代对象序列化为一连串值。