iterator是es6提供用于访问数据遍历的一种机制。
就是数据类型中被提供了Symbol.iterator 接口
**
概念
JavaScript 原有的表示“集合”的数据结构,主要是数组(Array)和对象(Object),ES6 又添加了Map和Set。这样就有了四种数据集合,用户还可以组合使用它们,定义自己的数据结构,比如数组的成员是Map,Map的成员是对象。这样就需要一种统一的接口机制,来处理所有不同的数据结构。
遍历器(Iterator)就是这样一种机制。它是一种接口,为各种不同的数据结构提供统一的访问机制。任何数据结构只要部署 Iterator 接口,就可以完成遍历操作(即依次处理该数据结构的所有成员)。
Iterator 的作用有三个:一是为各种数据结构,提供一个统一的、简便的访问接口;二是使得数据结构的成员能够按某种次序排列;三是 ES6 创造了一种新的遍历命令for...of循环,Iterator 接口主要供for...of消费。
Iterator 的遍历过程是这样的。
(1)创建一个指针对象,指向当前数据结构的起始位置。也就是说,遍历器对象本质上,就是一个指针对象。
(2)第一次调用指针对象的next方法,可以将指针指向数据结构的第一个成员。
(3)第二次调用指针对象的next方法,指针就指向数据结构的第二个成员。
(4)不断调用指针对象的next方法,直到它指向数据结构的结束位置。
es6中默认自带Symbol.iterator接口有
原生Array
set
map
nodeList
以及类数组都可以使用for..of
迭代器接口封装**
1.定义function模拟迭代器
var it = makeIterator(['a', 'b']);it.next() // { value: "a", done: false }it.next() // { value: "b", done: false }it.next() // { value: undefined, done: true }function makeIterator(array) {var nextIndex = 0;return {next: function() {return nextIndex < array.length ?{value: array[nextIndex++], done: false} :{value: undefined, done: true};}};}
2.使用genterator为对象添加一个迭代器
var obj = {a:11,b:22,c:33,d:['hello word'],[Symbol.iterator]:function *(){for(j of Object.keys(obj)) {yield obj[j];}}}//print [...obj](4) [11, 22, 33, Array(1)]0: 111: 222: 333: ["hello word"]length: 4__proto__: Array(0)
3.封装一个原生迭代器
var obj3 = {a:2,b:3,c:5,d:['test']}为当前对象添加自定义封装一个迭代器obj3[Symbol.iterator] = function(){var arr = Object.keys(this);var lenth = Object.keys(this);let index = 0;return {next:function(){return index < lenth ? {value:arr[index++],done:false} : {done:true}}}}for(var j of obj3){console.log(j,obj3[j])}VM691:2 a 2VM691:2 b 3VM691:2 c 5VM691:2 d ["test"]
4.覆盖原生数组迭代器
Array.prototype[Symbol.iterator] = function * (){yield 1;yield 2}var arr = [1,2,3]//展开结果只有1,2[...arr](2) [1, 2]
6.定义一个类数组添加原生数组迭代器
let iterable2 = {0: 'a',1: 'b',2: 'c',length: 3,[Symbol.iterator]:Array.prototype[Symbol.iterator]};[...iterable2](3) ["a", "b", "c"]
调用迭代器场合
有一些场合会默认调用 Iterator 接口(即Symbol.iterator方法),除了下文会介绍的for...of循环,还有几个别的场合。
(1)解构赋值
对数组和 Set 结构进行解构赋值时,会默认调用Symbol.iterator方法。
let set = new Set().add('a').add('b').add('c');
let [x,y] = set;
// x='a'; y='b'
let [first, ...rest] = set;
// first='a'; rest=['b','c'];
(2)扩展运算符
扩展运算符(…)也会调用默认的 Iterator 接口。
// 例一
var str = 'hello';
[...str] // ['h','e','l','l','o']
// 例二
let arr = ['b', 'c'];
['a', ...arr, 'd']
// ['a', 'b', 'c', 'd']
上面代码的扩展运算符内部就调用 Iterator 接口。
实际上,这提供了一种简便机制,可以将任何部署了 Iterator 接口的数据结构,转为数组。也就是说,只要某个数据结构部署了 Iterator 接口,就可以对它使用扩展运算符,将其转为数组。
let arr = [...iterable];
(3)yield*yield*后面跟的是一个可遍历的结构,它会调用该结构的遍历器接口。
let generator = function* () {
yield 1;
yield* [2,3,4];
yield 5;
};
var iterator = generator();
iterator.next() // { value: 1, done: false }
iterator.next() // { value: 2, done: false }
iterator.next() // { value: 3, done: false }
iterator.next() // { value: 4, done: false }
iterator.next() // { value: 5, done: false }
iterator.next() // { value: undefined, done: true }
(4)其他场合
由于数组的遍历会调用遍历器接口,所以任何接受数组作为参数的场合,其实都调用了遍历器接口。下面是一些例子。
- for…of
- Array.from()
- Map(), Set(), WeakMap(), WeakSet()(比如
new Map([['a',1],['b',2]])) - Promise.all()
- Promise.race()
