JS的迭代器

20 阅读3分钟

1.迭代就是指可以从一个数据集中按照一定的顺序,不断取出数据的过程

①为各种数据结构,提供一个统一的、简便的访问接口

②使得数据结构的成员能够按某种次序排列

③[ES6]创造了一种新的遍历命令 for…of 循环,Iterator 接口主要供 for…of 消费。

2.迭代和遍历区别:迭代重视取出的过程,不一定数据取出来完。遍历是依次把数据取出。

3.迭代器是能调用next方法实现迭代的一个对象,该方法返回一个具有两个属性的对象。

①value 可迭代对象的下一个值 ②done 表示是否已经取出所有的是数据了,false表示有数据,true表示无数据了。

4.迭代器的使用 Symbol.iterator来生成迭代器

const arr = [1, 2, 3]
const iter1 = arr[Symbol.iterator]()   // 通过迭代器工厂函数` Symbol.iterator`来生成迭代器。
console.log(iter1) //Array Iterator {}
console.log(iter1.next()) //{value:1,done:false}
console.log(iter1.next()) //{value:2,done:false}
console.log(iter1.next()) //{value:3,done:false}
console.log(iter1.next()) //{value:undefined,done:true}

迭代器是取完最后一个值之后,即迭代器下一个值 done true时,迭代完成

5.特点:

①不同迭代器之间互不干扰

②迭代器对象可以被遍历也就是for of for(const i of arr[Symbol.iterator]())

③迭代器是可以被修改的

④当迭代器下一个值 done true时,可以一直调用next,但是会一直返回{value:undefined,done:true},不会报错。

6.工作原理

创建一个指针对象,指向当前数据结构的起始位置 第一次调用next方法时,指针指向数据结构的第一个成员 接下来调用next方法,指针后移,直到指向最后一个成员 每次调用 next 方法都会返回一个值,这个值是一个 object,包含两个属性,value 和 done。value表示具体的返回值,done 是布尔类型的,表示集合是否遍历完成,完成则返回 true,否则返回 false。

7.Iterator 原生应用场景

有些对象我们并没有为它们部署 Iterator 接口,但是仍然可以使用 for…of 进行遍历。这是因为在ES6中有些对象已经默认部署了这个接口。

原生具备 Iterator 接口的数据结构:

  • Array
  • set容器
  • map容器
  • String
  • 函数的 arguments 对象
  • NodeList 对象

对象没有部署这个接口,对象可能有各种各样的属性,不像数组的值是有序的,所以对对象遍历时根本不知道如何确定先后顺序,所以需要我们手动实现。

①普通的 for 循环是可以随时中断的,for…of 循环作为 for 和 forEach 的升级版同样是可以的

②迭代器对象除了有 next 方法,还有两个可选方法 return 方法和 throw 方法

③return 方法的使用场景是,当 for…of 循环提前退出,就会调用 return 方法。

④需要特别注意的是,return 方法必须有一个 object 类型的返回值

⑤我们在前面代码的基础上添加上 return 方法,并在 for…of 循环中采用 break 语句来中断循环,循环提前退出,自动调用 return 方法输出提前退出

⑥如果采用抛出异常的方式退出,会先执行 return 方法再抛出异常

let iteratorObj = {
    items: [1, 2, 'ljc'],
    // 部署Symbol.iterator属性
    [Symbol.iterator]: function () {
        let self = this
        let i = 0
        return {
            next: function () {
                // 类型转化为Boolean
                let done = (i >= self.items.length)
                // 数据确认
                let value = !done ? self.items[i++] : undefined
                // 数据返回
                return {
                    done,
                    value
                }
            },
            return () {
                console.log('提前退出');
                return {
                    done: true
                }
            }
        }
    }
}
for (let item of iteratorObj) {
    console.log(item); // 1
    break;
}

8.Iterator 接口使用场景

①解构赋值

②扩展运算符 ...

③yield* yield*后面跟的是一个可遍历的结构,它会调用该结构的遍历器接口。

let generator = function* () { 
                    yield 1;
                    yield* [2,3,4];
                    yield 5
                }