迭代器与生成器

迭代器

迭代器是被设计专用于迭代的对象,带有特定接口。所有的迭代器对象都拥有next()方法,会返回一个结果对象。该结果对象有两个属性:对应下一个值的value,以及一个布尔类型的 done,其值为true 时表示没有更多值可供使用。

function createIterator(items) {
    var i = 0
    return {
      next: function() {
        var done = (i >= items.length)
        var value = !done ? items[i++] : undefined
        return {
          done: done,
          value: value
        }
      }
    }
  }
  var iterator = createIterator([1, 2, 3])
  console.log(iterator.next()) // "{ value: 1, done: false }"
  console.log(iterator.next()) // "{ value: 2, done: false }"
  console.log(iterator.next()) // "{ value: 3, done: false }"
  console.log(iterator.next()) // "{ value: undefined, done: true }

生成器

生成器(generator)是能返回一个迭代器的函数。生成器函数由放在function关键字之后的一个星号(*)来表示,并能使用新的 yield 关键字。将星号紧跟在 function 关键字之后,或是在中间留出空格,都是没问题的,正如下例:

// 生成器
function *createIterator() {
    yield 1
    yield 2
    yield 3
}
// 生成器能像正规函数那样被调用,但会返回一个迭代器
let iterator = createIterator()
console.log(iterator.next().value) // 1
console.log(iterator.next().value) // 2
console.log(iterator.next().value) // 3

yield 关键字也是ES6新增的,指定了迭代器在被 next() 方法调用时应当按顺序返回的值。

生成器函数表达式

你可以使用函数表达式来创建一个生成器,只要在function关键字与圆括号之间使用一个星号( *)即可。例如:

function *createIterator(items) {
    for (let i = 0; i < items.length; i++) {
      yield items[i]
    }
  }
  let iterator = createIterator([1, 2, 3])
  console.log(iterator.next()) // "{ value: 1, done: false }"
  console.log(iterator.next()) // "{ value: 2, done: false }"
  console.log(iterator.next()) // "{ value: 3, done: false }"
  console.log(iterator.next()) // "{ value: undefined, done: true }"
  // 之后的所有调用
  console.log(iterator.next()) // "{ value: undefined, done: true }"

生成器对象方法

由于生成器就是函数,因此也可以被添加到对象中。例如,你可以在ES5 风格的对象字面量中使用函数表达式来创建一个生成器:

var o = {
    createIterator: function *(items) {
      for (let i = 0; i < items.length; i++) {
        yield items[i]
      }
    }
  }
  let iterator = o.createIterator([1, 2, 3])

你也可以使用ES6方法的速记法,只要在方法名之前加上一个星号(*)

var o = {
    *createIterator(items) {
      for (let i = 0; i < items.length; i++) {
        yield items[i]
      }
    }
  };
  let iterator = o.createIterator([1, 2, 3])

访问默认迭代器

你可以使用Symbol.iterator来访问对象上的默认迭代器,就像这样:

let values = [1, 2, 3]
let iterator = values[Symbol.iterator]()
console.log(iterator.next()) // "{ value: 1, done: false }"
console.log(iterator.next()) // "{ value: 2, done: false }"
console.log(iterator.next()) // "{ value: 3, done: false }"
console.log(iterator.next()) // "{ value: undefined, done: true }"

检测对象是否能迭代

既然 Symbol.iterator 指定了默认迭代器,你就可以使用它来检测一个对象是否能进行迭代,正如下例:


  function isIterable(object) {
    return typeof object[Symbol.iterator] === 'function'
  }

  console.log(isIterable([1, 2, 3])) // true
  console.log(isIterable("Hello")) // true
  console.log(isIterable(new Map())) // true
  console.log(isIterable(new Set())) // true
  console.log(isIterable(new WeakMap())) // false
  console.log(isIterable(new WeakSet())) // false

创建可迭代对象

开发者自定义对象默认情况下不是可迭代对象,但你可以创建一个包含生成器的Symbol.iterator属性,让它们成为可迭代对象。例如:

let collection = {
    items: [],
    * [Symbol.iterator] () {
      for(let item of this.items) {
        yield item
      }
    }
  }
  collection.items.push(1)
  collection.items.push(2)
  collection.items.push(3)
  for (let x of collection) {
    console.log(x)
  }

输出:

1
2
3
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

  • 原创文章&经验总结&从校招到A厂一路阳光一路沧桑 详情请戳www.codercc.com 主要知识点:迭代器、生成...
    你听___阅读 925评论 0赞 1
  • 循环的问题 迭代器 迭代器是被设计专用于迭代的对象,带有特定接口。所有的迭代器对象都拥有 next() 方法,会返...
    wangxia34阅读 424评论 0赞 0
  • https://zhuanlan.zhihu.com/p/26123333 要完全理解透生成器,需要我们先掌握三个...
    Lauzanhing阅读 465评论 0赞 0
  • 迭代器(Iterable) 简单来说,迭代器对象(my_list)可以让以下代码正常工作: 如果对象实现了__it...
    SOLAREST阅读 673评论 0赞 1
  • 一段关系中的气氛,取决于人们相信自己在其他人心中受重视的程度。我们要更多地使用正向的肯定,如重视、承认和赞同...
    李远红阅读 188评论 0赞 0

友情链接更多精彩内容