JavaScript迭代器与生成器

148 阅读2分钟

迭代

循环是迭代的基础,可以指定迭代的次数,以及每次迭代要执行的条件。

迭代器模式

在ECMAScript这个语境下,把有些结构称为可迭代对象(iterable),实现了正式的Iterable接口,而且可以通过迭代器Iterator消费。

可迭代协议

支持迭代的自我识别能力和创建实现Iterator接口的对象的能力

已实现Iterable接口的类型

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

实现

  • 暴露属性作为‘默认迭代器’,使用Symbol.iterator作为键

  • 迭代器属性引用一个迭代器工厂函数,工厂函数返回一个新迭代器

  • 在实际操作中并不需要工厂函数来生成迭代器,实现可迭代协议的所有类型都会自动兼容接收可迭代对象的任何语言特性,接收可迭代对象的原生语言特性包括:

      for of
      数组结构
      扩展操作符
      Array.from()
      创建集合
      创建映射
      Promise.all()
      Promise.race()
      yiled*
      
    

这些原生语言结构会在后台调用提供的可迭代对象的这个工厂函数,从而创建一个迭代器

迭代器协议

迭代器API使用next()方法在可迭代对象中遍历数据,每次成功调用next(),都会返回一个IteratorResult对象,包含迭代器返回的下一个值。

 可迭代对象
 let arr=['foo','bar']
 迭代器工厂函数
 arr[Symbol.iterator]
 迭代器
 let iter=arr[Symbol.iterator]()
 执行迭代
 iter.next()
 直到done true停止

终止迭代

return{done:true}

生成器

生成器的形式是一个函数,函数名称前面加*表示是一个生成器。可以定义函数的地方就可以定义生成器。箭头函数除外。

实现

调用生成器函数会产生一个生成器对象。刚开始处于暂停执行(suspended)状态。生成器对象也实现了Iterator接口,具有next()方法。next()让生成器开始或恢复执行。

 let a={
     *one(){console.log('one')},
     *two(){console.log('two')}
 }

yiled

  • 生成器对象作为可迭代对象
  • 使用yield实现输入和输出
  • 产生可迭代对象
  • 实现递归

生成器作为默认迭代器

提前终止生成器

与迭代器类似,生成器支持‘可关闭’,实现Iterator接口的对象一定有next()方法,还有一个可选的return()方法用于提前终止迭代器。生成器还有throw()

小结

迭代器与生成器的引入是为了更好的支持迭代模式。