ES6 - Iterator

本文参考:《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()

你可能感兴趣的:(ES6 - Iterator)