JS的迭代器和生成器

114 阅读2分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第13天,点击查看活动详情

迭代器

在JS中提到迭代,那就提一下迭代协议。

迭代协议具体分为两个协议:可迭代协议和迭代器协议。

  1. 可迭代协议允许 JavaScript 对象定义或定制它们的迭代行为。例如,在一个 for..of 结构中,哪些值可以被遍历到。
  2. 迭代器协议定义了产生一系列值(无论是有限个还是无限个)的标准方式。 大致意思是可迭代协议是规定一个对象怎么变成可迭代的,以及迭代时可以访问那些值。迭代器协议就是对一个可迭代的对象,进行取值操作,迭代器是一个对象,它定义一个序列,并在终止时可能返回一个返回值。 更具体地说,迭代器是通过使用 next()方法实现Iterator protocol 的任何一个对象,该方法返回具有两个属性的对象: value,这是序列中的 next 值;和 done ,如果已经迭代到序列中的最后一个值,则它为 true 。如果 value和done一起存在,则它是迭代器的返回值。

生成器

虽然自定义的迭代器是一个有用的工具,但由于需要显式地维护其内部状态,因此需要谨慎地创建。生成器函数提供了一个强大的选择:它允许你定义一个包含自有迭代算法的函数, 同时它可以自动维护自己的状态。 生成器函数使用 function*语法编写。

  1. yield :yield关键字使生成器函数执行暂停,yield关键字后面的表达式的值返回给生成器的调用者。它可以被认为是一个基于生成器的版本的return关键字。
  2. yield* :yield* [[expression]]。 yield* 表达式迭代操作数,并产生它返回的每个值。yield* 表达式expression本身的值是当迭代器关闭时返回的值(即done为true时)。
function* makeRangeIterator(start = 0, end = Infinity, step = 1) {
    for (let i = start; i < end; i += step) {
        yield i;
    }
}

// 一旦生成器函数已定义,可以通过构造一个迭代器来使用它。

var a = makeRangeIterator(1,10,2)
a.next() // {value: 1, done: false}
a.next() // {value: 3, done: false}
a.next() // {value: 5, done: false}
a.next() // {value: 7, done: false}
a.next() // {value: 9, done: false}
a.next() // {value: undefined, done: true}

yield*:可以yield 其它任意的可迭代对象,比如说数组、字符串、arguments 对象等等。

function* g1() {
  yield 2;
  yield 3;
  yield 4;
}

function* g2() {
  yield 1;
  yield* g1();
  yield 5;
}

var iterator = g2();

console.log(iterator.next()); // { value: 1, done: false }
console.log(iterator.next()); // { value: 2, done: false }
console.log(iterator.next()); // { value: 3, done: false }