生成器 - 精细的图形部分

杰夫·波斯尼克
Jeff Posnick

ECMAScript 6 规范草稿已经为现代 JavaScript 开发者带来了许多乐趣。在上一篇博文中,我们介绍了一些新的集合类和 for..of 迭代循环。在这篇博文中,我们将探讨与 for..of 循环密切相关的内容:生成器函数。

已经有大量的优质资料介绍了使用生成器的原因和方法。简而言之,生成器是创建迭代器的特殊函数,而迭代器是具有 next() 方法的对象,调用该方法即可获取值。在生成器函数中,关键字 yield 提供 next() 的值。使用 yield 会挂起生成器函数的执行,同时保持状态直至再次调用 next(),此时代码重新开始并继续执行,直到 yield 调用另一个值(或生成器函数终止)。生成器函数有几个规范用例,比如使用它们遍历 Fibonacci 序列中的数字。

介绍完这些基础知识后,让我们通过一个 JavaScript 示例来深入探讨一下,该示例介绍了使用生成器时的一些问题(也称为“棘手的问题”)。其中有大量注释,您可以在阅读代码之前先试玩一下实际版本

那么,代码有哪些重要的要点呢?

首先,构建生成器将产生一个具有自己独特状态的唯一迭代器,您可以将参数传递给可以控制行为的生成器构造函数。

其次,您可以在调用迭代器的 next() 方法时传入形参,该值将分配给上一次迭代器调用的 yield 语句左侧的任何值。这是改变迭代器输出的好方法,在这里,我们用它来控制生成的单词是否采用大写。如果您想要影响生成的第一个值,可以通过生成器构造函数的参数来实现。

最后,生成器可以生成有限或无限迭代器。如果您使用的是无限迭代器,请确保您有基于 yielded 值的某种终止条件,这种情况很容易意外地编写无限循环,尤其是在使用 for..of 进行迭代时。如果您通过调用 next() 来使用有限迭代器,那么所返回对象的 .done 属性会指示迭代是否已完成。

我们希望此示例以及网络上的其他资源可以激发您的兴趣,并促使您思考如何在自己的代码中使用生成器。Firefox 31 版(及更高版本)和 Chrome(含 39 版)均支持原生支持生成器。Regenerator 项目为其他浏览器提供了生成器支持,当然您也可以选择使用 Traceur。

感谢 Erik Arvidsson 帮助审核本文。