概念
MDN解释:非标准。 Iterator 函数是一个 SpiderMonkey 专有特性,并且会在某一时刻被删除。为将来使用的话,请考虑使用 for..of 循环和 迭代协议。(emmm 读了一遍,听君一席话,如听一席话!啥也没读懂)
其实遍历器(Iterator)是一种接口,为各种不同的数据结构提供统一的访问机制。任何数据结构只要部署Iterator接口,就可以完成遍历操作(即依次处理该数据结构的所有成员)。
再简单来说Iterator接口就是可遍历的标志,各种数据结构遍历靠的都是它!
关于详细概念可以参考 MDN ,这里主要分享一些学习中的体会。
作用
Iterator的作用有三个:
- 为各种数据结构,提供一个统一的、简便的访问接口;
- 使得数据结构的成员能够按某种次序排列;
- ES6创造了一种新的遍历命令
for...of循环,Iterator接口主要供for...of消费。
在ES6中,数据结构原生就部署Iterator接口的有数组、某些类似数组的对象(Array,Map,Set,String,TypedArray,函数的 arguments 对象,NodeList 对象,字符串)、Set和Map结构。它们即不用任何处理,就可以被for...of循环遍历。
为对象添加Iterator接口的例子
let obj1 = {
data: [ 'hello', 'world' ],
[Symbol.iterator]() {
const self = this;
let index = 0;
return {
next() {
if (index < self.data.length) {
return {
value: self.data[index++],
done: false
};
} else {
return { value: undefined, done: true };
}
}
};
}
};
let obj2={ 0:"hello", 1:"word" }
//遍历模拟了iterator接口的对象obj1
for (const key of obj1) {
console.log(key);
}
//遍历没有iterator接口的对象obj2
for (const key of obj2) {
console.log(key);
}
运行结果
可以看出obj1成功遍历,而obj2遍历报错(obj2不存在iterator接口,不能被遍历)
类数组对象调用数组的Symbol.iterator方法
let iterable = {
0: 'a',
1: 'b',
2: 'c',
length: 3,
[Symbol.iterator]: Array.prototype[Symbol.iterator]
};
for (let item of iterable) {
console.log(item); // 'a', 'b', 'c'
}
学习中遇到的困难
学习Array.keys()(keys() 方法返回一个数组索引的迭代器。)时,遇到这样两个例子,
例1:
var array = ["abc", "xyz"];
var iterator = array.keys();
console.log(iterator); //[ Object [Array Iterator] {} ] 自己尝试的
console.log(iterator.next()); // Object {value: 0, done: false}
console.log(iterator.next()); // Object {value: 1, done: false}
console.log(iterator.next()); // Object {value: undefined, done: false}
例2:
var array = ["abc", , "xyz"];
var iterator = [...array.keys()];
console.log(iterator); // [0, 1, 2]
为什么例1中的iterator = array.keys() 为array数组索引的迭代器,通过iterator.next()调用下一个元素,此时输出iterator为[ Object [Array Iterator] {} ],但是例2中的iterator = [...array.keys()],输出iterator却为[0, 1, 2],想不通为什么,后来查了一圈才知道ES6-扩展运算符(...)会默认调用Iterator接口(即Symbol.iterator方法),所以可以输出[0, 1, 2]。
除了ES6-扩展运算符(...)还有一些会默认调用Iterator接口的场合
- for...of
- 解构赋值
- 扩展运算符(...)
- yield*_yield*后面跟的是一个可遍历的结构,它会调用该结构的遍历器接口。
- 由于数组的遍历会调用遍历器接口,所以任何接受数组作为参数的场合,其实都调用。