概念
iterator是接口的一种机制,为各种不同类型的数据提供统一的访问机制,使不同数据结构可以按照某种次序排列。iterator接口主要供 ES6中新增的for..of循环消费~
内置iterator接口
字符串 数组 映射 集合 arguments对象 NodeList等DOM集合类型
let str = 'abc';let arr = ['a', 'b', 'c'];let map = new Map().set('a', 1).set('b', 2).set('c', 3);let set = new Set().add('a').add('b').add('c');let els = document.querySelectorAll('div');// 调用这个工厂函数会生成一个迭代器console.log(str[Symbol.iterator]()); // StringIterator {}console.log(arr[Symbol.iterator]()); // ArrayIterator {}console.log(map[Symbol.iterator]()); // MapIterator {}console.log(set[Symbol.iterator]()); // SetIterator {}console.log(els[Symbol.iterator]()); // ArrayIterator {}
接收可迭代对象
- for-of 循环
- 数组解构
- 扩展操作符
- Array.from()
- 创建集合
- 创建映射
- Promise.all()接收由期约组成的可迭代对象
- Promise.race()接收由期约组成的可迭代对象
- yield*操作符,在生成器中使用
执行顺序
- 创建一个指针对象,指向当前数据的起始位置。
- 调用指针的next方法,将指针指向数据的第一个成员。
- 不断调用next方法,直到它指向数据结构的结束位置。
手写Iterator
let arr = iterator(['a','b','c'])function iterator(arr){let index = 0;return {next(){return index < arr.length ? {value:arr[index++],done:false}:{next:undefined,done:true}}}}console.log(arr.next()); // {value: "a", done: false}console.log(arr.next()); // {value: "b", done: false}console.log(arr.next()); // {value: "c", done: false}console.log(arr.next()); // {next: undefined, done: true}
原生iterator
原生js中也有好多默认实现了iterator接口。比如:Array、arguments、Set、Map、String、NodeList都通过了默认iterator接口

let arr = ['banana', 'apple', 'orange']// 得到arr中iterator 接口let arrNext = arr[Symbol.iterator]()console.log(arrNext.next()); // {value: "banana", done: false}console.log(arrNext.next()); // {value: "apple", done: false}console.log(arrNext.next()); // {value: "orange", done: false}console.log(arrNext.next()); // {value: undefined, done: true}
let str = 'bac'let iterStr = str[Symbol.iterator]();iterStr.next(); // {value: "b", done: false}iterStr.next(); // {value: "a", done: false}iterStr.next(); // {value: "c", done: false}iterStr.next(); // {value: undefined, done: true}
for.of
上面我们说了,只有提供了
iterator接口的才能使用for.of循环。
// 当然如果不信的话 我们可以循环object测试一下let obj = {name: "前端伪大叔",age: 19,like: 'web'}for (k of obj) {console.log(k); // iterator.html:59 Uncaught TypeError: obj is not iterableat iterator.html:59}// 当然也可以使用下面方法部署 iterator接口for (k of Reflect.ownKeys(obj)) {console.log(`${k}:${obj[k]}`);// 但是如果你继续在查找原型上查找的话 还是会找到iterator属性~~~~console.log(Reflect.ownKeys(obj).__proto__); // Symbol(Symbol.iterator): ƒ values()}for(k of Object.keys(obj)){console.log(`${k}:${obj[k]}`);console.log(Object.keys(obj).__proto__); // Symbol(Symbol.iterator): ƒ values()}
总结
iterator接口是为了解决ES5的for..in 循环遗留下不能循环value的bug,如果需要使用for..of遍历的话可以加上iterator接口就可以实现遍历
