js迭代器的理解

183 阅读3分钟

参考:js高级程序设计第四版

理解迭代

  • 循环是迭代的基础,es5之前的循环有其缺点:
    1. 迭代之前需要事先知道如何使用数据结构
    2. 遍历顺序并不是数据结构固有的,不适用所有的数据结构
  • 无需知道如何迭代就能实现迭代操作

迭代器模式

概念

  • 是一个方案:可以把有些结构称为‘可迭代对象(iterable)’
  • 因为它们实现了正式的iterable接口,而且可以通过迭代器iterator消费。

实现了iterator接口的结构:一个工厂函数,类等等。默认是类似以下的工厂函数:

[Symbol.iterator]() {
    return {
      next() {
        return {
          done: false,
          value: 'foo'
        }
      }
    }
  }

迭代器是按需创建的一次性对象:

{ next() { return { done: false, value: 'foo' } } }

,每个迭代器都会关联一个可迭代对象,迭代器会暴露api去迭代这个关联对象。 这个next函数就是iterator接口可以遍历有Symbol.iterator这个属性的数据结构(必须是可迭代的iterable),只需要知道如何取得关联可迭代对象的连续的值。

  • 可迭代对象是抽象说法,可理解为数组或者集合类型的对象。元素有限,有无歧义的遍历顺序

也不一定是集合对象,类似数组行为的其他数据结构如计数循环。临时性可迭代对象可实现为生成器

可迭代协议

实现iterable(可迭代协议)要有两种能力:

  • 支持迭代的自我识别能力
  • 创建实现iterator接口的对象的能力(具有Symbol.iterator属性)

暴露一个属性为默认迭代器,必须使用特殊的Symbol.iterator作为键,引用一个迭代器工厂函数,返回一个新迭代器 字符串,数组,映射,集合,arguments对象,NodeList等DOM集合类型等都实现了iterable接口 检查是否存在默认迭代器属性:

console.log(num[Symbol.iterator])
  • 实现可迭代协议的所有类型都会自动兼容接收可迭代对象的任何语言特性。 for-of 解构 扩展操作符 Array.from 创建集合/映射 Promise.all/Promise.race 接收由期约组成的可迭代对象 这些原生语言结构会再后台调用提供的可迭代对象的这个工厂函数,从而创建一个迭代器

迭代器协议

迭代器是一种一次性使用的对象,用于迭代与其关联的可迭代对象。

自己对js迭代器的理解

const arr = ['foo', 'baz', 'bar']

const iter = arr[Symbol.iterator]()

console.log(iter.next())
console.log(iter.next())
console.log(iter.next())
console.log(iter.next())
console.log(iter.next())
console.log(iter.next())

// { value: 'foo', done: false }
// { value: 'baz', done: false }
// { value: 'bar', done: false }
// { value: undefined, done: true }
// { value: undefined, done: true }
// { value: undefined, done: true }
  • arr是可迭代的,实现了可迭代协议:
  1. 支持迭代的自我识别能力(数组毋庸置疑)
  2. 有创建实现iterator接口的对象的能力(有Symbol.iterator这个默认属性,属性值是一个工厂函数,可以创建一个---实现iterator接口的对象即迭代器)
  • 迭代器(上面的iter就是迭代器):
  1. 是一种一次性使用的对象
  2. 用于迭代与其关联的可迭代对象
  3. 使用next()方法在可迭代对象中遍历数据

每次成功调用next(),都会返回iteratorResult对象。{done:false,value: 'foo'}。 - 每个迭代器之间相互独立 - 不与迭代器绑定。中途修改了会反映相应变化

//这个类实现了可迭代接口(Iterable)
//调用默认的迭代器工厂函数会返回
//一个实现迭代器接口(Iterator)的迭代器对象
class Foo {
  [Symbol.iterator]() {
    return {
      next() {
        return { done: false, value: "foo" };
      },
    };
  }
}
let f = new Foo();
// 打印出实现了迭代器接口的对象
console.log(f[Symbol.iterator]());// {next:f(){}}

//Array类型实现了可迭代接口(Iterable)
//调用Array类型的默认迭代器工厂函数
//会创建一个ArrayIterator的实例
let a = new Array();
//打印出ArrayIterator的实例
console.log(a[Symbol.iterator]()); //Array Iterator

自定义迭代器

与iterable类似。任何实现iterator接口的对象都可以作为迭代器使用。