1、遍历器(Iterator)是一种接口,为各种不同的数据结构提供统一的访问机制。任何数据结构只要部署Iterator接口,就可以完成遍历操作(即依次处理该数据结构的所有成员)。
2、Iterator的作用有三个:一是为各种数据结构,提供一个统一的、简便的访问接口;二是使得数据结构的成员能够按某种次序排列;三是ES6创造了一种新的遍历命令for...of
循环,Iterator接口主要供for...of
消费。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
// 要达到的效果 先遍历one在遍历two let obj = { one: [1, 3, 2], two: [7, 8, 9], // 这里是一个函数--返回的是有.next()方法的 [Symbol.iterator]() { //里面自定义规则 let objThis = this; let index = 0; //当前索引 let arr = objThis.one.concat(objThis.two); //先把这个数组合并出来 let len = arr.length; //记录新数组的长度 return { next() { // 这里是写自定义遍历的方法 // (自定义循环条件方法)有二个参数必须返回出来value和done if (index < len) { //小与数组长度的在这执行 return { value: arr[index++], //返回数组中的内容,并且索引值++ done: false //这是next一个属性,最后找不到返回true } } else { return { value: arr[index++], done: true } //没找到输出 } } } } } for (let key of obj) { console.log(key); //输出结果1 3 2 7 8 9 // 如果没有自定义接口,是输出不了会报错没有这方法的 } |
3、在ES6中,有些数据结构原生具备Iterator接口(比如数组),即不用任何处理,就可以被for...of
循环遍历,有些就不行(比如对象)。原因在于,这些数据结构原生部署了Symbol.iterator
属性(详见下文),另外一些数据结构没有。凡是部署了Symbol.iterator
属性的数据结构,就称为部署了遍历器接口。调用这个接口,就会返回一个遍历器对象。
4、在ES6中,有三类数据结构原生具备Iterator接口:数组、某些类似数组的对象、Set和Map结构。
5、一个为对象添加Iterator接口的例子。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
let obj = { data: [ 'hello', 'world' ], [Symbol.iterator]() { const self = this; let index = 0; return { next() { if (index < self.data.length) { return { value: self.data[index++], done: false }; } else { return { value: undefined, done: true }; } } }; } }; |
6、下面是类似数组的对象调用数组的Symbol.iterator
方法的例子。
1 2 3 4 5 6 7 8 9 10 |
let iterable = { 0: 'a', 1: 'b', 2: 'c', length: 3, [Symbol.iterator]: Array.prototype[Symbol.iterator] }; for (let item of iterable) { console.log(item); // 'a', 'b', 'c' } |
注意,普通对象部署数组的Symbol.iterator
方法,并无效果。
7、有一些场合会默认调用Iterator接口(即Symbol.iterator
方法),除了下文会介绍的for...of
循环,还有几个别的场合。
- 解构赋值
- 扩展运算符(...)
- yield*_yield*后面跟的是一个可遍历的结构,它会调用该结构的遍历器接口。
- 由于数组的遍历会调用遍历器接口,所以任何接受数组作为参数的场合,其实都调用
8、字符串是一个类似数组的对象,也原生具有Iterator接口。
9、遍历器对象除了具有next
方法,还可以具有return
方法和throw
方法。如果你自己写遍历器对象生成函数,那么next
方法是必须部署的,return
方法和throw
方法是否部署是可选的。