JavaScript 常见设计模式----迭代器模式

62 阅读2分钟

1.介绍

普通for循环不是迭代器

const arr = [10, 20, 30]
const length = arr.length
for (let i = 0; i < length; i++) {
  console.log(arr[i]); 
}

简易迭代器:

const pList = document.querySelectorAll('p')
pList.forEach(p=>console.log(p))

2.小结

  • 顺序访问有序结构(如数组、NodeList)
  • 不知道数据的长度和内部结构
  • 高内聚,低耦合

3.迭代器模式代码演示

class DataIterator{
  private data: number[]
  private index: number = 0
  constructor(container: DataContainer) {
    this.data = container.data
  }
  next () {
    if (this.hasNext()) {
      return this.data[this.index++]
    }
    return null
  }
  hasNext () {
    if (this.index >= this.data.length) {
      return false
    }
    return true
  }
}
class DataContainer{
  data = [10, 20, 30, 40, 50]
  getIterator (): DataIterator {
    return new DataIterator(this)
  }
}

const container = new DataContainer()
const iterator = container.getIterator()
while(iterator.hasNext()) {
  console.log(iterator.next()); 
}

4.是否符合设计原则

  • 使用者和目标分离,解耦
  • 目标能自行控制其内部逻辑
  • 使用者不关心目标的内部结构

5.迭代器模式-使用场景

  • 有序结构
  • Symbol.iterator和迭代器
  • 迭代器的应用

1.有序结构

  • 字符串
  • 数组
  • Map
  • Set
  • NodeList等DOM集合
  • arguments

2.Symbol.iterator

image.png 自定义迭代器:

interface 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...of
  • 数组:解构、扩展操作符、Array.from
  • 用于创建Map和Set
  • 用于Promise.all和Promise.race
  • 用于 yield *

Generator 生成器

  • 基本使用
  • yield * 语法
  • yield 遍历DOM树
function* genNums () {
  // yield 1
  // yield 2
  // yield 3
  yield* [1, 2, 3]
}
//生成器函数返回的是迭代器,如 arr[Symbol.iterator]()
const numsIterator = genNums()
//console.log(numsIterator.next()) //{value: 1, done: false}
//console.log(numsIterator.next()) //{value: 2, done: false}
//console.log(numsIterator.next()) //{value: 3, done: false}
//console.log(numsIterator.next()) //{value: undefined, done: true}
for(let n of numsIterator) {
  console.log(n) // 1,2,3
}
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)
}

使用Generator 遍历DOM树

function* traverse (elemList: Element[]): any {
  for (const elem of elemList) {
    yield elem
  }
  const children = Array.from(elemList.children)
  if(children.length) {
    yield* traverse(children)
  }
}
const container = document.querySelector('#container')
 if(container) {
   const iterator = traverse([container])
   for(let elem of iterator) {
     console.log(elem)
   }
 }

注意事项

  • Object 不是有序结构
  • 简单的for循环不是迭代器,迭代器是解决for循环的问题