初始迭代器
说到迭代器,大家是不是马上就能想到Array
、Map
、Set
这些名词呢?
所以这些就是迭代器。。。。。吧?
答案是:错!惊不惊喜?意不意外?
说到迭代器这个概念,首先我们应该明确:迭代器(Iterator
)只是一个接口,而Array
、Set
、Map
是我们熟知的不同的数据结构,而这些数据结构他们原生的就已经实现了这个Iterator
接口。除开这几个数据结构,还有String
、Arguments
、TypedArray
以及DOM
中的NodeList
和Collection
总结:Array、Set、Map、Arguments、String、NodeList、Collection、TypedArray
实现Iterator
接口后,相应的数据结构就具备了迭代能力(如下)
let arr = [1,2,3];
for(let ele of arr) {
console.log(ele);
}
// 1
// 2
// 3
可迭代协议
可以通过检查实例的[Symbol.iterator]属性,来判断是否存在默认迭代器属性(也就是判断是否实现了迭代器接口)
let arr = new Array();
let str = new String();
let map = new Map();
let set = new Set();
// 当然还有一些NodeList等DOM集合类型
console.log(arr[Symbol.iterator]); // ƒ values() { [native code] }
console.log(str[Symbol.iterator]); // ƒ [Symbol.iterator]() { [native code] }
console.log(map[Symbol.iterator]); // ƒ entries() { [native code] }
console.log(set[Symbol.iterator]); // ƒ values() { [native code] }
console.log(arr[Symbol.iterator]()); // 返回迭代器 Array Iterator {}
console.log(str[Symbol.iterator]()); // 返回迭代器 StringIterator {}
console.log(map[Symbol.iterator]()); // 返回迭代器 MapIterator {}
console.log(set[Symbol.iterator]()); // 返回迭代器 SetIterator {}
如果对象原型链上的父类实现了Iterable接口,那这个对象也就实现了这个接口
class SonArray extends Array {}
let son_arr = new SonArray(11,23,34);
/* 包含[Symbol.iterator]属性 */
console.log(son_arr[Symbol.iterator]().__proto__.__proto__); // {Symbol(Symbol.iterator): ƒ}
for(let ele of son_arr) {
console.log(ele);
}
// 11
// 23
// 34
迭代器协议
为什么实现了迭代器接口就可以具有遍历的能力呢?
我们通过查看实例的Symbol.iterator方法的返回值,可以发现返回的迭代器对象的原型对象上实现了next()
才使得数据结构具有了迭代的能力(后面有通过next()
自定义实现迭代器方式)
let arr = new Array(12,23);
let iter = arr[Symbol.iterator]();
console.log(iter); // Array Iterator {}
console.log(iter.next()); // {value: 12, done: false}
console.log(iter.next()); // {value: 23, done: false}
console.log(iter.next()); // {value: undefined, done: true}
console.log(iter.next()); // {value: undefined, done: true}
如果可迭代对象在迭代期间被修改,那么迭代器也会反映相应的变化
let arr = ['fly','swim'];
let iter = arr[Symbol.iterator]();
console.log(iter.next()); // {value: "fly", done: false}
// 添加值
arr.splice(1, 0, 'code');
console.log(iter.next()); // {value: "code", done: false}
console.log(iter.next()); // {value: "swim", done: false}
console.log(iter.next()); // {value: undefined, done: false}
自定义迭代器
当你真的搞清楚了迭代器的原理,你就可以手动的给任何数据结构添加可迭代能力
下面针对不同版本自定义了不同的实现方式,供大家参考
ES5
function Number(num1, num2, num3) {
this.num1 = num1;
this.num2 = num2;
this.num3 = num3;
this.args = arguments;
}
Number.prototype[Symbol.iterator] = function() {
// 定义计数器
let count = 0;
// 存储参数集合
let Args = this.args;
return {
next() {
if(count < Args.length) {
return { done: false, value: Args[count++] };
}else {
return { done: true, value: undefined };
}
}
}
};
let numList = new Number(11,23,34);
console.log(numList);
for(let ele of numList) {
console.log(ele);
}
// 11
// 23
// 34
for(let ele of numList) {
console.log(ele);
}
// 11
// 23
// 34
ES6
class Person {
constructor(name,age,skill) {
this.name = name;
this.age = age;
this.skill = skill;
this.Args = arguments;
}
// 实现Iterator接口
[Symbol.iterator]() {
// 定义计数器
let count = 0;
// 存储所有参数
let AllArgs = this.Args;
/*
返回一个迭代器对象
- 这个对象需要实现next()方法
*/
return {
next() {
if(count < AllArgs.length) {
return { done: false, value: AllArgs[count++] };
}else {
return { done: true, value: undefined };
}
}
};
}
}
let person = new Person('leo',20,'play code');
console.log(person);
let iter = person[Symbol.iterator]();
console.log(iter.next()); // {done: false, value: "leo"}
console.log(iter.next()); // {done: false, value: 20}
console.log(iter.next()); // {done: false, value: "play code"}
console.log(iter.next()); // {done: true, value: undefined}
console.log(iter.next()); // {done: true, value: undefined}
for(let ele of person) {
console.log(ele);
}
// leo
// 20
// play code