ECMA6-JavaScript中生成器功能的使用

inv*_*ess 5 javascript ecmascript-6

我花了几天的时间来了解ES6版本中引入的JavaScript中的Generator函数。

发电机的地方有很多,但对我来说似乎很有趣的是,到处都有

生成器函数是一种同步编写异步代码的方法。

我要提出的问题是“为什么仅出于此目的就需要引入一种完全不同的编程策略?”

我了解JS代码的异步特性使新手很难理解和调试代码,但是是否需要彻底改变编码风格?

我可能错了或者没有完全理解其引入背后的概念,但是对所有事物的好奇心促使我提出这个问题。

Sha*_*ger 4

因为闭包对于简单迭代不太方便;即使语言之前支持相同的模式,简化相当常见的任务的语法也是值得的。比较一下:

function chain() {
    var args = Array.from(arguments);
    return function() {
        if (args.length === 0) return undefined; // Or some other sentinel
        var nextval = args[0].shift(); // Destructive to avoid copies or more closure vars
        if (args[0].length === 0) args.shift();
        return nextval;
    };
}
var x;
// a, b and c must be indexable, e.g. Arrays; we can't handle other closures without
// requiring some API specific protocol for generation
for (var nextchain = chain(a, b, c); (x = nextchain()) !== undefined;) {
    // do stuff with current value
}
Run Code Online (Sandbox Code Playgroud)

到:

function* chain() {
    for (var i = 0; i < arguments.length; ++i)
        yield* arguments[i];
}
// a, b and c can be any iterable object; yield* can handle
// strings, Arrays, other generators, etc., all with no special handling
for (var x of chain(a, b, c)) {
    // do stuff with current value
}
Run Code Online (Sandbox Code Playgroud)

当然,代码行数的节省并不令人难以置信。它主要只是减少样板文件和不必要的名称,消除了处理简单情况的闭包的需要,并通过语法for...of提供了一种通用机制来迭代任意可迭代的事物,而不是要求用户显式构造初始闭包并通过以下方式推进它:姓名。但如果该模式足够常见,那就足够有用了。

正如评论中所指出的,a, b, c必须Array类似于基于闭包的方法(或者您会使用不同的基于闭包的方法,其中编写者对chain传递给它的东西强加任意要求,特殊情况下是Array类似的东西与类似生成器的东西闭包)并且处理是破坏性的(您需要添加更多闭包状态或制作副本以使其非破坏性,从而使其更复杂或更慢);对于基于生成器的方法yield*,不需要特殊情况。这使得生成器无需复杂的规格即可组合;他们可以轻松地相互构建。