迭代器(Iterator)

Iterator 是一个接口 为各种数据结构统一封装了一个遍历方法(只要部署了 Iterator 接口)主要给 for of 去消费的

Iterator 作用

  • 统一了历史上各种数据结构的访问接口
  • 提供了一个 for-of 命令来循环

以上 有几个点

  1. 接口? 如何实现
  2. 统一数据结构? 如何不统一了

Iterator 接口

在 js 语言中 没有接口这么一个概念 我们尝试理解为一个迭代器对象

  1. 迭代器对象结构
  next: function() {
    return {
      value: xxx,  // 结果值
      done: true || false  // 来检测是否遍历完
    }
  },复制代码
  1. 我们模拟实现下
  function makeIterator(list) {
    var index = 0
    return {  // 返回一个可迭代的对象
      next:function() {
        return index >list.length?
        {
          value: undefined, done: true
        }
        :
        {
          value: list[index++], done: false
        }
      }
    }
  }
  var it = makeIterator(['a', 'b', 'c']);
  console.log(it.next())  //{value: "a", done: false}
  console.log(it.next())  //{value: "b", done: false}
  console.log(it.next())  //{value: "c", done: false}
  console.log(it.next())  //{ value: undefined, done: true}复制代码

那这个跟 for-of 有啥关系 跟统一了数据结构有啥关系那?带着问题往下看

看下场景

var arr = ['a','b','c'] 遍历数组 arr 能想到的方法

  • case1
      for(let i=0; i<arr.length; i++) {
        console.log(arr[i])
      }复制代码
  • case2
      arr.forEach(item => {
        console.log(item)
      })复制代码
  • case3
      for(var i in arr) {
        console.log(i arr[i])  // 0 1 2 // a b c
      }复制代码
  • case4for(var i of arr) { console.log(i) // a b c }

    var str ='abc' 遍历字符串同样的这么多 case

会发现遍历一个资源 有很多方法 有没有一个统一的方法 for-of 来了

for-of

阮一峰ES6 借鉴 C++、Java、C# 和 Python 语言,引入了 for...of 循环,作为遍历所有数据结构的统一的方法.

for-of 不是对所有资源都能遍历 只有实现了(通过 Iterator 接口包装的)Iterator 接口的才能使用 for-of (换句话说就是 一个资源上有了 Iterator 接口(Symbol.iterator) 就能使用 for-of 来使用了)

  • 普通对象 不能 被使用 因为普通对象上没有 Symbol.iterator 属性 // 普通数组使用报错
  • 字符串可以使用 字符串上有 Symbol.iterator 默认属性
  • 普通数组可以使用 因为数组默认带了 Symbol.iterator 属性

问题来了 普通对象如何才能使用?

普通对象 被 for-of 消费

  1. 我们来模拟实现下

    只要将普通对象包装一个 Symbol.iterator 接口就行

   var markObjectIterator = {
    items: {a:1,b:2,c:3},
    [Symbol.iterator]: function() {
        var self = this;
        var i = 0;
        return {
            next: function () {
                var done = (i >= Object.keys(self.items).length);
                var value = !done ? self.items[Object.keys(self.items)[i++]] : undefined;
                return {
                    done: done,
                    value: value
                };
            }
        };
    }}

   for(var item of markObjectIterator) {
    console.log(item)
   }复制代码

总结

  • 熟悉 es6 代码
  • code 一个简易迭代器接口
  • 实现一个 for-of 消费的简易的可迭代对象
  • 对 Symbol.iterator 下章详解