遍历器的概念
遍历器(iterator)的作用有三个:一是为各种数据结构提供统一的遍历接口,二是使数据结构的成员按照一定的顺序进行排列,三是为遍历命令 for...of 消费。
function makeIterator(arr) {
let index = 0;
return {
next: () => {
return index < arr.length ? { value: arr[index++], done: false } : { value: undefined, done: true };
},
};
}
const iterator = makeIterator(["a", "b"]);
console.log(iterator.next()); // { value: 'a', done: false }
console.log(iterator.next()); // { value: 'b', done: false }
console.log(iterator.next()); // { value: undefined, done: true }
使用 makeIterator 方法创建遍历器对象后,就可以调用里面的 next 方法,它会返回每个成员的信息对象,其中 value 是成员的值,有就返回没有就返回 undefined,而 done 是表示是否完成遍历,true 表示遍历结束。
iterator 接口
一个数据结构有 iterator 接口,也就是拥有 Symbol.iterator 属性,就说该数据结构是可遍历的。
原生具有 iterator 接口的数据结构有 String,Array,Set,Map,TypedArray,NodeList,函数的 arguments 对象。没有 iterator 接口的数据结构可以通过增加 Symbol.iterator 属性的方式,来实现数据结构的可遍历。
class RangeIterator {
constructor(start, end) {
this.start = start;
this.end = end;
}
[Symbol.iterator]() {
return this;
}
next() {
let index = this.start;
if (index < this.end) {
this.start++;
return { value: index++, done: false };
} else {
return { value: undefined, done: true };
}
}
}
const range = new RangeIterator(0, 3);
const res = range[Symbol.iterator]();
console.log(res.next()); // { value: 0, done: false }
console.log(res.next()); // { value: 1, done: false }
console.log(res.next()); // { value: 2, done: false }
console.log(res.next()); // { value: undefined, done: true }
for (var value of range) {
console.log(value); // 0, 1, 2
}
RangeIterator 实例对象增加 Symbol.iterator 属性后,就说明该对象是可遍历的。这时候可以调用 Symbol.iterator 属性提供的函数得到实例对象,再通过调用里面的 next() 方法获取值。通过 for...of 遍历 RangeIterator 实例对象可以直接在每次遍历的时候打印获取值。
除了自定义实现一个 iterator 接口,也可以借助其他数据结构原生提供的 iterator 接口
let iterable = {
0: "a",
1: "b",
2: "c",
length: 3,
[Symbol.iterator]: Array.prototype[Symbol.iterator],
};
const ttt = iterable[Symbol.iterator]();
console.log(ttt.next()); // { value: 'a', done: false }
console.log(ttt.next()); // { value: 'b', done: false }
console.log(ttt.next()); // { value: 'c', done: false }
console.log(ttt.next()); // { value: undefined, done: false }
for (const item of iterable) {
console.log(item); // a b c
}
类数组对象 iterable 借助了数组的 Symbol.iterator 属性来部署自身的 Symbol.iterator 属性,该对象可以通过使用 Symbol.iterator 属性的方法再加上 next() 来获取值,也可以直接通过 for..of 来遍历里面的数据
小结
本文首先介绍了拥有 iterator 接口的数据结构,再介绍了给数据结构增加 iterator 接口的两种方法,自定义创建和借助其他数据结构实现。最后总结了 iterator 的三个作用。