什么是Iterator(遍历器)
Iterator是一种机制,一种接口,为各种不同的数据结构提供统一的访问机制。任何数据结构,只要部署Iterator接口,就可以完成遍历操作。遍历其实是一种线性处理,有序的。
Iterator遍历的过程:
- 1、创建一个遍历指针,指向当前数据结构的起始位置
- 2、第一次调用指针对象的next方法,返回第一个成员
- 3、第二次调用next方法,返回第二个成员
- 4、不断的调用next方法,直到指针对象指向数据结构的结束位置
//获取遍历器
var arr = [1,2][Symbol.iterator]();
arr.next(); //{value: 1, done: false}
arr.next(); //{value: 2, done: false}
arr.next(); //{value: undefined, done: true}
arr.next(); //{value: undefined, done: true}
返回的成员信息是一个对象,包含{value: any, done: boolean}。调用指针对象的next方法就可以遍历事先给定的数据结构。
由于Iterator只是把接口规范加到数据结构上,所以遍历器和所遍历的数据结构是分开的。
什么是遍历器生成函数
默认的Iterator接口部署在数据结构的Symbol.iterator属性上,属性对应的值就是遍历器生成函数,所以只要具有Symbol.iterator属性就可以遍历。如果Symbol.iterator方法反应的不是遍历器对象生成函数,就好报错。
执行Symbol.iterator属性就会返回一个遍历器对象。该对象的根本特征就是具有next方法,每次调用next就会返回一个代表当前成员的信息对象,具有value和done两个属性。
const obj = {
a: 'aa',
[Symbol.iterator]: function(){
return {
next(){
return {
value: 1,
done: true,
}
}
}
}
}
var objIterator = obj[Symbol.iterator]();
objIterator.next(); //{value: 1, done: true}
objIterator.next(); //{value: 1, done: true}
当使用for...of循环遍历某种数据结构时,就会自动去寻找Iterator接口
//无限循环,谨慎执行
for(let value of obj){
console.log(value); //1
}
原生具备Iterator接口的数据结构:
- Array
- Set
- Map
- String
- TypeArray
- 函数的argument对象
- NodeList对象
- Generator对象
对象(Object)没有Iterator接口,因为对象属性遍历先后顺序是不确定的。
Iterator接口与Generator函数
Symbol.iterator最简单的实现方式
var myIterator = {};
myIterator[Symbol.iterator] = function*(){
yield 1;
yield* [2, 3];
yield 4;
}
[...myIterator] //[1,2,3,4]
for...of循环与for..in循环的区别
一个数据结构只要部署了Symbol.iterator数据,就被视为具有Iterator接口,就可以使用for...of循环它的成员。
for...of循环调用接口,数组的遍历接口只返回具有数字索引的属性。
var arr = [1,2];
a[3] = 3;
arr.a = 'aa';
for(let value of arr){
console.log(value);
}
// 1 2 empty 3
for(let value in arr){
console.log(value);
}
// '0' '1' '3' 'aa'
for...in循环遍历缺点:
- 只能获得对象的键名,不能直接获取键值
- 不仅遍历数字键名,遍历手动添加的其他键名,甚至包括原型链上的键
- 某些情况下以任意顺序遍历键名
for...in循环主要为遍历对象而设计的,不适用于遍历数组
for...of循环遍历优点:
- 不同于forEach方法,它可以与break、continue、return配合使用
- 提供了遍历所有数据结构的统一接口
- 对于字符串,可以识别32位UTF-16字符
for...of会把数组中空值也给遍历处理
对象的遍历,最好采用Object.keys + for...of
var obj = {
a: 'aa',
b: 'bb'
};
for(let key of Object.keys(obj)){
console.log(key, obj[key])
}
//'a' 'aa'
//'b' 'bb'