迭代器模式就是为了解决遍历的问题。

在ES6之前,数组内置的遍历方法无法用于类数组的遍历。类数组和数组都是集合,然而针对这两种数据却要写两套遍历逻辑,这显然很坑。当然,我们可以通过使用 JQ 中的 each 方法来实现两种数据的遍历,可是这样我们就要引入 JQ 库,这样也好麻烦。

# ES6对迭代器的实现

直到 ES6 出现,在 ES6 中又新增了 set 和 map 两种数据结构。结合之前的数组和对象就是四种数据结构了,它们各自有各自的内部实现,这样去遍历就更麻烦了。还好 ES6 推出了一套统一的接口机制 - 迭代器。ES6 规定任何数据只要实现了 Symbol.iterator 属性(这个属性就是Iterator的具体实现,它本质上是当前数据结构默认的迭代器生成函数)就可以被遍历,更准确的可以说是被 for...of 和代器的 next 方法遍历。实际上 for...of 背后也是 next 的方法的调用来实现的。

拿数组举例,我们可以使用 for...of 来遍历数组:

const arr = [1, 2, 3, 4]
for (let item of arr) {
  console.log(item)
}
/* 
1
2
3
4
*/

之所以我们能使用 for...of 对数组进行遍历,是因为数组通过 Symbol.iterator 生成了对应的迭代器对象。可以通过不断调用 next 方法实现遍历。

const arr = [1, 2, 3, 4]
const iterator = arr[Symbol.iterator]();

console.log(iterator.next());
console.log(iterator.next());
console.log(iterator.next());
console.log(iterator.next());
console.log(iterator.next());

/* 
{value: 1, done: false}
{value: 2, done: false}
{value: 3, done: false}
{value: 4, done: false}
{value: undefined, done: true}
 */

for...of 的操作基本等价与下面的操作:

const arr = [1, 2, 3, 4]
// 生成迭代器对象
const iterator = arr[Symbol.iterator]()
// 初始化一个迭代结果
let now = { done: false }

// 遍历
while(!now.done) {
  now = iterator.next()
  if (!now.done) {
    console.log(now.value)
  }
}

/* 
1
2
3
4
*/

# 实现迭代器生成函数

ES6 内置了生成器,我们可以通过它来实现一个迭代器生成函数。

function *iteratorGenerator() {
  yield '1'
  yield '2'
  yield '3'
}
const iterator = iteratorGenerator()

console.log(iterator.next())
console.log(iterator.next())
console.log(iterator.next())

/* 
控制台输出:

{value: "1", done: false}
{value: "2", done: false}
{value: "3", done: false}
*/

可以看到借助 ES6 的生成器来实现一个生成器函数并不难,但是如果让你不借助 ES6 的生成器来实现一个迭代器生成函数改怎么实现呢?

从前面所学我们先来做个简单分析:调用迭代器生成函数会返回一个对象,这个对象有一个 next 属性,它的值是一个函数,调用 next 后会返回一个对象,这个对象有两个属性,分别是 done 和 value。如果需迭代的数据还没有遍历完 done 的值为false, value 为当前遍历的值,如果数据已经遍历完 done 的值为 true ,value 的值为 undefined 。

通过上面的分析我们可以写出个大体框架

// 伪代码
function iteratorGenerator(list) {
  return {
    next() {
      reutrn {
        value:xxx
        done:xxx
      }
    }
  }
}

下面我们来完善一下 value 和 done 的值。

function iteratorGenerator(list) {
  let idx = 0;
  const len = list.length;
  return {
    next() {
      let done = idx >= len;
      let value = !done ? list[idex++] : undefined;
      reutrn {
        value,
        done
      }
    }
  }
}

测试下我们自己写的迭代器生成函数:

const arr = [1, 2, 3, 4];
const iterator = iteratorGenerator(arr)
console.log(iterator.next());
console.log(iterator.next());
console.log(iterator.next());
console.log(iterator.next());
console.log(iterator.next());

/* 
控制台输出:

{value: 1, done: false}
{value: 2, done: false}
{value: 3, done: false}
{value: 4, done: false}
{value: undefined, done: true}
*/

可以看到完美运行了。