本文参考:《ECMAScript 6入门》阮一峰
概念:Iterator是一种接口,为各种不同的数据结构提供统一的访问机制。任何数据结构只要部署Iterator接口,就可以完成遍历操作(即依次处理该数据结构的所有成员)。
作用:
- 1. 为数据结构提供访问接口
- 2. 对于任何非线性的数据结构,部署遍历器接口,就等于部署一种线性转换
- 3. 供
for of
消费
一. for of
遍历机制
-
for of
其实调用了部署好的Iterator接口,但是并不是所有数据结构都原生部署了Iterator接口(比如object),这就是为什么for of
没法遍历object的原因。 - 这里的部署了了Iterator接口,其实就是说拥有一个
Symbol.iterator
属性 - 原生部署了Iterator接口的数据结构有(也就是说可遍历的):
数据结构 | 描述 |
---|---|
Array | 数组 |
Set / Map | ES6提出的数据结构 |
arguments | 参数对象(类数组) |
DOM NodeList 对象 | 类数组 |
Generator 对象 | ES6 |
string | 字符串 |
二. Iterator接口遍历的过程
- Iterator接口最基本应该具有next方法。(return和throw方法见《ECMAScript 6入门》)
function makeIterator(arr){
let pos = 0;
return {
next(){
if(pos < arr.length){
return { value:arr[pos++],done:false };
}else{
return { value:undefined,done:true };
}
}
}
}
makeIterator
方法返回一个对象,该对象拥有一个next方法。
makeIterator
方法同时维护了一个pos指针,指向参数数组的第一个元素。
当next第一次执行时,返回一个对象{ value:第一个元素的值, done:false }
,其中done表示还没有遍历完所有元素。指针指向下一个元素。
三. 如何将Iterator接口部署到数据结构上
- 上面提到过,Iterator接口有一个作用是供
for of
消费,前提是该数据结构有一个Symbol.iterator
属性。 - 当数据结构原生没有部署
Symbol.iterator
属性但又想使用for of
怎么解决?
1. 为object部署Iterator接口
function obj2iterable(obj){
let temp = [];
for(let key in obj){
temp.push(obj[key]);
}
return {
data:temp,
[Symbol.iterator](){
let index = 0;
const _self = this;
return {
next(){
if(index < _self.data.length){
return { value:_self.data[index++],done:false };
}else{
return { value:undefined,done:true };
}
}
}
}
}
}
obj2iterable
方法可以处理一个对象,返回一个具有Iterator接口的新对象。
let obj1 = {
name:'tom',
age:{
hobby:21
}
}
for(let i of obj2iterable(obj1)){
console.log(i);
}
// tom
// { hobby: 21 }
2. 为类数组对象部署Iterator接口
- 类数组对象存在数值键名和length属性,部署Iterator接口,有一个简便方法,就是Symbol.iterator方法直接引用数组的Iterator接口。
let ArrayLike = {
0:'tom',
1:'jack',
2:12,
length:3,
[Symbol.iterator]: Array.prototype[Symbol.iterator]
}
for(let i of ArrayLike){
console.log(i);
}
// tom
// jack
// 12
四. 除了for of
还有什么情况会调用Iterator接口呢?
(一)解构赋值
(二)扩展运算符
(三)yield*
(四)Array.from()
(五)Map(), Set(), WeakMap(), WeakSet()
(六)Promise.all()、Promise.race()
网友评论