概念

iterator 是接口的一种机制,为各种不同类型的数据提供统一的访问机制,使不同数据结构可以按照某种次序排列。 iterator 接口主要供 ES6中新增的for..of 循环消费~

内置iterator接口

字符串 数组 映射 集合 arguments对象 NodeList等DOM集合类型

  1. let str = 'abc';
  2. let arr = ['a', 'b', 'c'];
  3. let map = new Map()
  4. .set('a', 1)
  5. .set('b', 2)
  6. .set('c', 3);
  7. let set = new Set()
  8. .add('a')
  9. .add('b')
  10. .add('c');
  11. let els = document.querySelectorAll('div');
  12. // 调用这个工厂函数会生成一个迭代器
  13. console.log(str[Symbol.iterator]()); // StringIterator {}
  14. console.log(arr[Symbol.iterator]()); // ArrayIterator {}
  15. console.log(map[Symbol.iterator]()); // MapIterator {}
  16. console.log(set[Symbol.iterator]()); // SetIterator {}
  17. console.log(els[Symbol.iterator]()); // ArrayIterator {}

接收可迭代对象

  • for-of 循环
  • 数组解构
  • 扩展操作符
  • Array.from()
  • 创建集合
  • 创建映射
  • Promise.all()接收由期约组成的可迭代对象
  • Promise.race()接收由期约组成的可迭代对象
  • yield*操作符,在生成器中使用

执行顺序

  • 创建一个指针对象,指向当前数据的起始位置。
  • 调用指针的next方法,将指针指向数据的第一个成员。
  • 不断调用next方法,直到它指向数据结构的结束位置。

    手写Iterator

    1. let arr = iterator(['a','b','c'])
    2. function iterator(arr){
    3. let index = 0;
    4. return {
    5. next(){
    6. return index < arr.length ? {
    7. value:arr[index++],
    8. done:false
    9. }:{
    10. next:undefined,
    11. done:true
    12. }
    13. }
    14. }
    15. }
    16. console.log(arr.next()); // {value: "a", done: false}
    17. console.log(arr.next()); // {value: "b", done: false}
    18. console.log(arr.next()); // {value: "c", done: false}
    19. console.log(arr.next()); // {next: undefined, done: true}

    原生iterator

    原生js中也有好多默认实现了iterator接口。比如:Array、arguments、Set、Map、String、NodeList都通过了默认iterator接口

image.png

  1. let arr = ['banana', 'apple', 'orange']
  2. // 得到arr中iterator 接口
  3. let arrNext = arr[Symbol.iterator]()
  4. console.log(arrNext.next()); // {value: "banana", done: false}
  5. console.log(arrNext.next()); // {value: "apple", done: false}
  6. console.log(arrNext.next()); // {value: "orange", done: false}
  7. console.log(arrNext.next()); // {value: undefined, done: true}
  1. let str = 'bac'
  2. let iterStr = str[Symbol.iterator]();
  3. iterStr.next(); // {value: "b", done: false}
  4. iterStr.next(); // {value: "a", done: false}
  5. iterStr.next(); // {value: "c", done: false}
  6. iterStr.next(); // {value: undefined, done: true}

for.of

上面我们说了,只有提供了 iterator 接口的才能使用 for.of 循环。

  1. // 当然如果不信的话 我们可以循环object测试一下
  2. let obj = {
  3. name: "前端伪大叔",
  4. age: 19,
  5. like: 'web'
  6. }
  7. for (k of obj) {
  8. console.log(k); // iterator.html:59 Uncaught TypeError: obj is not iterableat iterator.html:59
  9. }
  10. // 当然也可以使用下面方法部署 iterator接口
  11. for (k of Reflect.ownKeys(obj)) {
  12. console.log(`${k}:${obj[k]}`);
  13. // 但是如果你继续在查找原型上查找的话 还是会找到iterator属性~~~~
  14. console.log(Reflect.ownKeys(obj).__proto__); // Symbol(Symbol.iterator): ƒ values()
  15. }
  16. for(k of Object.keys(obj)){
  17. console.log(`${k}:${obj[k]}`);
  18. console.log(Object.keys(obj).__proto__); // Symbol(Symbol.iterator): ƒ values()
  19. }

总结

iterator接口是为了解决ES5的for..in 循环遗留下不能循环value的bug,如果需要使用for..of遍历的话可以加上iterator接口就可以实现遍历