美文网首页
迭代器与生成器

迭代器与生成器

作者: 小小的白菜 | 来源:发表于2018-10-02 15:31 被阅读0次

迭代器

迭代器是被设计专用于迭代的对象,带有特定接口。所有的迭代器对象都拥有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

相关文章

网友评论

      本文标题:迭代器与生成器

      本文链接:https://www.haomeiwen.com/subject/xzynoftx.html