Iterator迭代器
遍历器(Iterator) 是一种机制(接口):为各种不同的数据结构提供统一的访问机制,任何数据结构只要不是 Iterator 接口,就可以完成遍历操作「for of 循环」,依次处理该数据结构的所有成员「拥有 next 方法用于依次遍历数据结构的成员」,每一次遍历返回的结果是一个对象:
{
done: false, // 记录是否遍历完成
value: xxx // 当前遍历的结果
}
实现一个 Iterator 类
由于内置没有 Iterator 类,我们根据它的规范,手动实现一个类,接收一个集合「数组、类数组对象」,返回一个迭代器对象。
class Iterator {
constructor(data) {
this.data = data;
this.index = 0;
}
next() {
// 迭代完了
if (this.index > this.data.length - 1) {
return {
done: true,
value: undefined
}
}
return {
done: false,
value: this.data[this.index++]
}
}
}
let itor = new Iterator([10, 20, 30, 40]);
console.log(itor.next());
console.log(itor.next());
console.log(itor.next());
console.log(itor.next());
console.log(itor.next());
Symbol.iterator
虽然浏览器没有内置的 Iterator,但是它给很多数据结构,都提供了迭代的接口方法 Symbol.iterator,具备这个接口的数据结构,就可以基于 for of 进行循环迭代了
- 数组、类数组「arguments/NodeList/HTMLCollection」、字符串、Set/Map、generator object..
- Object.prototype 上是不具备 Symbol.iterator
// ƒ values() { [native code] }
console.log(Array.prototype[Symbol.iterator]);
console.log(String.prototype[Symbol.iterator]);
console.log(NodeList.prototype[Symbol.iterator]);
console.log(HTMLCollection.prototype[Symbol.iterator]);
console.log(Set.prototype[Symbol.iterator]);
console.log(Map.prototype[Symbol.iterator]);
修改 Symbol.iterator
// for of 遍历的时候,先调用对象的 [Symbol.iterator],获取一个迭代器实例 itor
// 每一轮循环,都是 itor.next() 执行,并且把返回对象的 value 值拿到
// 当返回对象中 done 为 true 的时候,结束循环
Array.prototype[Symbol.iterator] = function values() {
let self = this;
let index = 0;
return {
next() {
if (index > self.length - 1) {
return {
done: true,
value: undefined
}
}
return {
done: false,
value: self[index++]
}
}
}
}
var arr = [10, 20, 30];
for (let value of arr) {
console.log(value);
}
赋予for of遍历对象的能力
怎么能让 for of 遍历对象呢?
// 前置只是
// @1 取对象 key 时,一定要注意包含对象自身的 Symbol key 值
// @2 getOwnPropertySymbols 是 Object 的静态属性,不在原型链上
Object.prototype[Symbol.iterator] = function values() {
let self = this;
let keys = Object.keys(this).concat(Object.getOwnPropertySymbols(this));
let index = 0;
return {
next() {
if (index > keys.length - 1) {
return {
done: true,
value: undefined
}
}
return {
done: false,
value: self[keys[index++]]
}
}
}
}
var obj = {
name: 'ys',
age: 10,
0: 100,
1: 200
};
for (let value of obj) {
console.log(value); // 100 200 ys 10
}
赋予for of遍历类数组的能力
var obj = {
0: 10,
1: 20,
2: 30,
3: 40,
length: 4
}
obj[Symbol.iterator] = Array.prototype[Symbol.iterator];
for (let value of obj) {
console.log(value);
}