迭代器模式就是为了解决遍历的问题。
在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}
*/
可以看到完美运行了。
← 观察者模式