这是我参与「第五届青训营」伴学笔记创作活动的第 5 天
1. 主要内容
概念介绍,解决的问题
代码演示和 UML 类图
应用场景 + Generator 生成器
1)学习方法
UML 类图要结合代码理解
设计模式要结合使用场景,否则会记不住
2)注意事项
一开始可能听不懂,坚持一下,后面会豁然开朗
简单的 for 循环不是迭代器
2. 普通 for 循环不是迭代器
存在非常明显的缺陷漏洞,我们需要知道数组长度,如何获取每个元素
一旦获取长度和获取每个元素方法更改,那么就会出现错误
1)简易迭代器
2)迭代器总结
顺序访问有序结构(如数组、NodeList)
不知道数据的长度和内部结构
高内聚,低耦合
3. 迭代器模式
UML 类图
代码演示
是否符合设计原则
1)UML 类图
2)代码演示
class DataContainer {
data: number[] = [10, 20, 30, 40, 50];
getIterator(): DatIterator {
return new DatIterator(this);
}
}
class DatIterator {
private data: number[];
private index: number = 0;
constructor(container: DataContainer) {
this.data = container.data;
}
next(): number | null {
if (this.hasNext()) {
return this.data[this.index++];
}
return null;
}
hasNext(): boolean {
if (this.index >= this.data.length) {
return false;
}
return true;
}
}
const container = new DataContainer();
const iterator = container.getIterator();
while (iterator.hasNext()) {
console.log(iterator.next());
}
3)是否符合设计原则
使用者和目标分离,解耦
目标能自行控制其内部逻辑
使用者不关心目标的内部结构
4)总结
UML 类图
代码演示
符合设计原则
4. 迭代器模式 - 场景
有序结构
Symbol.iterator 和迭代器
迭代器的应用
1)有序结构
字符串
数组
NodeList 等 DOM 集合
Map
Set
arguments
2)模拟 Symbol.iteraotr 迭代器
class IteratorRes {
value: number | undefined;
done: boolean;
}
class CustomIterator {
private length = 3;
private index = 0;
next(): IteratorRes {
this.index++;
if (this.index <= this.length) {
return { value: this.index, done: false };
}
return { value: undefined, done: true };
}
[Symbol.iterator]() {
return this;
}
}
const iterator = new CustomIterator();
// console.log(iterator.next());
// console.log(iterator.next());
// console.log(iterator.next());
// console.log(iterator.next());
for (const n of iterator) {
console.log(n);
}
3)迭代器的作用
用于 for...of(附:对比 for...in )
- 只有存在
Symbol.iterator方法的有序数组,都可以用 for...of 进行遍历 - 什么类似数据存在
Symbol.iterator:1)有序结构
数组:结构、扩展运算符、Array.from(将伪数组变成数组)
用于创建 Map 和 Set
用于 Promise.all 和 Promise.race
用于 yield *
4)总结
有序结构有哪些:1)有序结构
Symbol.iterator 和迭代器
- 所有的有序结构都有内置迭代器
- 手写一个迭代器:2)模拟 Symbol.iteraotr 迭代器
迭代器的应用
5. Generator 生成器
基本使用
yield * 语法
yield 遍历 DOM 树
1)生成器语法
function* getNums(){
yield 10
yield 20
yield 30
}
const numsIterator = getNums() // 生成一个迭代器,如 arr[Symbol.iterator]()
for (let n of numsIterator){
console.log(n)
}
// ----------------------------- 分割线 -----------------------------
function* getNums(){
yield* [11, 21, 31] // 有序结构,已经实现了[Symbol.iterator]
}
const numsIterator = getNums() // 生成一个迭代器,如 arr[Symbol.iterator]()
for (let n of numsIterator){
console.log(n)
}
2)利用 Generator 生成器重构 CustomIterator
class CustomIterator {
private data: number[]
constructor(){
this.data = [100, 200, 300]
}
* [Symbol.iterator](){
yield* this.data
}
}
const iterator = new CustomIterator()
for (let n of iterator){
console.log(n)
}
3)Generator + yield 遍历 DOM 树
以后凡是涉及到遍历的操作,都可以使用生成器来进行遍历
// ts 内容
function* traverse(elemList: Element[]): any {
for (const elem of elemList) {
yield elem;
const children = Array.from(elem.children);
if (children.length) {
yield* traverse(children);
}
}
}
const container = document.getElementById("app");
if (container) {
for (const node of traverse([container])) {
console.log(node);
}
}
// html 内容
<div id="container">
<p class="text"><b>hello everybody 我是DJ喜羊羊</b></p>
<p>为了来表演,我提前打败了灰太狼</p>
<div>
<img src="https://oss.flrjcx.cn/client/images/avatar-uisdc-chat.png"/>
</div>
</div>
4)总结
基本使用
yield * 语法
yield 遍历 DOM 树
6. 内容回顾
概念介绍,解决的问题
代码演示和 UML 类图
应用场景:Smybol.iterator + Generator
7. 重要细节
for...of 和迭代器的关系
Generator 和迭代器的关系
Object 不是有序结构
8. 注意事项
简单的 for 循环不是迭代器,迭代器是解决 for 循环的问题