概述
JS 中有 4 种表示“集合”的数据结构:Array、Set、Object、Map。我们也可以组合使用它们来定义自己的数据结构。这样就需要一种统一的接口机制,来处理所有不同的数据结构。
Iterator(遍历器/迭代器)就是这样的一种机制,它是一种接口,为各种不同的数据结构提供统一的访问机制。任何数据结构只要部署 Iterator 接口,就可以完成遍历操作(即依次处理该数据结构的所有成员)。
我们看一个遍历器生成函数示例,初步了解一下遍历器:
1 | function makeIterator(arr) { |
我们先来了解一下可遍历和不可遍历的数据结构
数组是可遍历的,为什么呢?因为它拥有 [Symbol.iterator]()
方法( Iterator 接口),我们输出一个数组,然后可以在它的原型中找到这个方法,
1 | let arr = ['a', 'b', 'c'] |
我们再调用一下这个方法:
1 | let it = arr[Symbol.iterator]() |
再定义一个不可遍历的数据结构,并使用 for … of 遍历,它就会报错,错误提示就是它没有 [Symbol.iterator]()
方法。
1 | let courses = { |
我们在这里讲一下 可迭代协议 和 迭代器协议:
可迭代协议:如果一个数据结构具有 Symbol.iterator
方法,那么它就是可迭代的,否则它就是不可迭代的。如果是可迭代的,就可以使用 for … of 进行迭代。
迭代器协议:迭代器必须返回如右所示的结构的对象:{ next(){ return {value, done} } }
那么有哪些数据结构原生就具备 Iterator 接口呢?
- Array
- Map
- Set
- String
- TypedArray(描述的是二进制缓存区一个类似数组的视图,也叫类型数组)
- 函数的 arguments 对象
- NodeList 对象
使用 Iterator 将不可遍历的数据结构改造成“可遍历”的
我们拿上面定义的 courses 作为示例。根据可迭代协议,如果想让 courses 变成可迭代的,需要给它加上 Symbol.iterator
方法。再根据迭代器协议的返回值要求来编写。
1 | courses[Symbol.iterator] = function() { |
此时我们再用 for … of 遍历,输出如下:
使用 Generator 实现 Iterator
上一篇博客讲到了 Generator,Generator 函数返回值是一个对象,这个对象也有 next() 方法,并且 next() 方法的返回值也是一个包含 value 和 done 属性的对象。因为我们可以使用 Generator函数 来实现 Iterator。
1 | courses[Symbol.iterator] = function* () { |
总结
- Iterator 是一种接口机制,为不同的数据结构提供统一访问的机制
- Iterator 主要供 for … of 消费
- Iterator 将不支持遍历的数据结构变得“可遍历”