简介

  1. 是一种接口机制,为各种不同的数据结构提供统一访问的机制
  2. 主要供for … of 消费
  3. 让不支持遍历的数据结构”可遍历”,最强大之处

手写遍历器

  1. function makeIterator(arr) {
  2. let nextIndex = 0
  3. return {
  4. next() {
  5. return nextIndex < arr.length ? {
  6. value: arr[nextIndex++],
  7. done: false
  8. } : {
  9. value: undefined,
  10. done: true
  11. }
  12. }
  13. }
  14. }
  15. let it = makeIterator(['a', 'b', 'c'])
  16. console.log('it:', it.next())
  17. console.log('it:', it.next())
  18. console.log('it:', it.next())
  19. console.log('it:', it.next())

image.png

支持Iterator接口的数据

image.png

用map数据进行举例

let map = new Map()
map.set('name', 'es')
map.set('age', 5)
map.set('school', 'imooc')

let it = map[Symbol.iterator]()
console.log('it:', it.next())
console.log('it:', it.next())
console.log('it:', it.next())
console.log('it:', it.next())

image.png

手写底层迭代器

const course = {
  allCourse: {
    pc: ['es', '小程序', 'vue', 'react'],
    backend: ['java', 'python', 'springboot'],
    app: ['Android', 'ios']
  }
}

for (let data of course) {
  console.log('data', data)
}

image.png

自行实现next() 方法

可迭代协议:Symbol.iterator
迭代器协议::return {next(){return {value, done}}}

const course = {
  allCourse: {
    pc: ['es', '小程序', 'vue', 'react'],
    backend: ['java', 'python', 'springboot'],
    app: ['Android', 'ios']
  }
}

course[Symbol.iterator] = function () {
  let allCourse = this.allCourse
  let keys = Reflect.ownKeys(allCourse)
  console.log('keys:', keys)
  let values = []
  return {
    next(){
      // 因为初始化的时候,values是空数组,长度为0,需要取反
      if (!values.length) {
        if (keys.length) {
          values = allCourse[keys[0]]
          keys.shift()
        }
      }
      return {
        // 这里有个细节,先判断长度然后执行shift() ,避免对长度判断出错
        done: !values.length,
        value: values.shift()
      }
    }
  }
};
for (let data of course) {
  console.log('遍历', data)
}

image.png
这种处理办法虽然看起来很繁琐,但是很适合处理大型项目中复杂数据结构无法遍历,我们可以通过这种方式来重构 for of 循环的底层遍历原理,实现数据的遍历

与generator相结合

const course = {
  allCourse: {
    pc: ['es', '小程序', 'vue', 'react'],
    backend: ['java', 'python', 'springboot'],
    app: ['Android', 'ios']
  }
}

course[Symbol.iterator] = function* () {
  let allCourse = this.allCourse
  let keys = Reflect.ownKeys(allCourse)
  let values = []
  while (1) {
    if (!values.length) {
      if (keys.length) {
        values = allCourse[keys[0]]
        keys.shift()
        yield values.shift()
      } else {
        return false
      }
    } else {
      yield values.shift()
    }
  }
};

for (let data of course) {
  console.log('generator遍历', data)
}

image.png