组件库项目中运用的迭代器模式 | 青训营笔记

128 阅读2分钟

这是我参与「第五届青训营」伴学笔记创作活动的第 5 天

1. 主要内容

概念介绍,解决的问题

代码演示和 UML 类图

应用场景 + Generator 生成器

1)学习方法

UML 类图要结合代码理解

设计模式要结合使用场景,否则会记不住

2)注意事项

一开始可能听不懂,坚持一下,后面会豁然开朗

简单的 for 循环不是迭代器

2. 普通 for 循环不是迭代器

image-20230110130820205

存在非常明显的缺陷漏洞,我们需要知道数组长度,如何获取每个元素

一旦获取长度和获取每个元素方法更改,那么就会出现错误

1)简易迭代器

image-20230110131129058

2)迭代器总结

顺序访问有序结构(如数组、NodeList)

不知道数据的长度和内部结构

高内聚,低耦合

3. 迭代器模式

UML 类图

代码演示

是否符合设计原则

1)UML 类图

image-20230110143322614

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);
 }

image-20230110145948357

3)迭代器的作用

用于 for...of(附:对比 for...in )

  • 只有存在 Symbol.iterator 方法的有序数组,都可以用 for...of 进行遍历
  • 什么类似数据存在 Symbol.iterator1)有序结构

数组:结构、扩展运算符、Array.from(将伪数组变成数组)

用于创建 Map 和 Set

用于 Promise.all 和 Promise.race

用于 yield *

4)总结

有序结构有哪些:1)有序结构

Symbol.iterator 和迭代器

迭代器的应用

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 循环的问题