遍历器(Iterator)就是这样一种机制。它是一种接口,为各种不同的数据结构(数组、Set、Map等)提供统一的访问机制。任何数据结构只要部署 Iterator 接口,就可以完成遍历操作(即依次处理该数据结构的所有成员)供 for…of消费。

    for…of遍历机制:

    • 会寻找被遍历对象是否含有Symbol.iterator方法,如果没有报错
    • 当for…of遍历的时候,会调用遍历器对象的next方法
    • 当done为false的时候继续遍历,为true的时候,停止遍历

    想要被for…of 遍历:

    • 部署Symbol.iterator方法,返回迭代器对象iterator object
    • 迭代器对象中提供next方法被for…of遍历
    • next方法返回 {value: any,done:Boolean}

    原生具备 Iterator 接口的数据结构如下。

    • Array
    • Map
    • Set
    • String
    • TypedArray
    • 函数的 arguments 对象
    • NodeList 对象

    对象(Object)之所以没有默认部署 Iterator 接口,是因为对象的哪个属性先遍历,哪个属性后遍历是不确定的,需要开发者手动指定。本质上,遍历器是一种线性处理,对于任何非线性的数据结构,部署遍历器接口,就等于部署一种线性转换

    部署了遍历器的数据结构我们称为是可迭代的(iterable),也就是可以:

    • for..of
    • rest、spread 扩展运算符
    • yield*
    • Array.from()

    举例:
    Object对象正常是不可迭代的
    image.png
    要想range可迭代,我们按照以上步骤来实现下:

    1. let range = {
    2. from: 1,
    3. to: 5,
    4. };
    5. // 1. for..of 调用首先会调用这个:
    6. range[Symbol.iterator] = function () {
    7. // ……它返回迭代器对象(iterator object):
    8. // 2. 接下来,for..of 仅与此迭代器一起工作,要求它提供下一个值
    9. return {
    10. current: this.from,
    11. last: this.to,
    12. // 3. next() 在 for..of 的每一轮循环迭代中被调用
    13. next() {
    14. // 4. 它将会返回 {done:.., value :...} 格式的对象
    15. if (this.current <= this.last) {
    16. return { value: this.current++, done: false };
    17. } else {
    18. return { value: undefined, done: true };
    19. }
    20. },
    21. };
    22. };
    23. for (let r of range) {
    24. console.log(r);
    25. }

    字符串原生就部署了遍历器

    1. const str = 'helllo';
    2. const iterator = str[Symbol.iterator]();
    3. iterator.next(); //{value: 'h', done: false}
    4. iterator.next(); //{value: 'h', done: false}
    5. iterator.next(); //{value: 'h', done: false}
    6. ...

    iterator与generator

    1. let range = {
    2. from: 1,
    3. to: 5,
    4. *[Symbol.iterator]() { // [Symbol.iterator]: function*() 的简写形式
    5. for(let value = this.from; value <= this.to; value++) {
    6. yield value;
    7. }
    8. }
    9. };