什么是迭代器? 如何实现一个迭代器?

241 阅读1分钟

「这是我参与2022首次更文挑战的第 4 天,活动详情查看:2022首次更文挑战」。

什么是迭代器?

迭代器是帮助我们对某个数据结构进行遍历的对象, 它有一个 next 方法, next 方法返回一个对象

{
  done: boolean, // 为 true 时代表迭代完毕
  value: any     // done 为 true 时取值为 undefined
}

模拟实现一个迭代器:

function test1() {
  function createArrayIterator(arr) {
    let index = 0
    return {
      next: () =>
        index < arr.length
          ? { value: arr[index++], done: false }
          : { value: undefined, done: true },
    }
  }

  // 测试
  const nums = [11, 22, 33, 44]
  const numsIterator = createArrayIterator(nums)
  console.log(numsIterator.next())
  console.log(numsIterator.next())
  console.log(numsIterator.next())
  console.log(numsIterator.next())
  console.log(numsIterator.next())
}
test1()

可迭代对象

实现了生成迭代器方法的对象称为 可迭代对象 也就是说这个对象中包含一个方法, 该方法返回一个迭代器对象 一般使用 Symbol.iterator 来定义该属性, 学名叫做 @@iterator 方法

function test2() {
  // 一个可迭代对象需要具有[Symbol.iterator]方法,并且这个方法返回一个迭代器
  const obj = {
    names: ['111', '222', '333'],
    [Symbol.iterator]() {
      let index = 0
      return {
        next: () =>
          index < this.names.length
            ? { value: this.names[index++], done: false }
            : { value: undefined, done: true },
        return: () => {
          console.log('迭代器提前终止了...')
          return { value: undefined, done: true }
        },
      }
    },
  }
  for (const item of obj) {
    console.log(item)
    if (item === '222') break
  }
}
test2()

这样我们就可以使用 for of 等方法对该对象就行遍历了, 并且当遍历中途停止的时候, 还会调用迭代器对象的 return 方法 一些原生实现了 @@iterator 方法的对象: String、Array、Map、Set、arguments 对象, 所以我们才能对这些对象进行遍历

使用生成器来创建一个迭代器

我们知道生成器函数的返回值就是一个迭代器对象, 所以我们可以使用生成器来创建迭代器

function test3() {
  const obj = {
    names: ['111', '222', '333'],
    [Symbol.iterator]: function* () {
      for (const name of this.names) {
        yield name
      }
    },
  }
  for (const item of obj) {
    console.log(item)
  }
}
test3()

或者使用 yield* 这个语法糖使得代码更简洁:

const obj = {
  names: ['111', '222', '333'],
  [Symbol.iterator]: function* () {
    yield* this.names
  },
}

主要是学习一些原生对象为什么可以被遍历的原理, 实际开发中使用场景较少