能否将 ECMAScript 6 生成器重置为初始状态?

40

在提供的(非常简单的)生成器中,是否可以将生成器返回到其原始状态以便再次使用?

var generator = function*() {
    yield 1;
    yield 2;
    yield 3;
};

var iterable = generator();

for (let x of iterable) {
    console.log(x);
}

// At this point, iterable is consumed.
// Is there a method for moving iterable back
// to the start point by only without re-calling generator(),
// (or possibly by re-calling generator(), only by using prototype 
//  or constructor methods available within the iterable object)
// so the following code would work again?

for (let x of iterable) {
    console.log(x);
}

我希望能够将可迭代对象传递给其他作用域,在其上进行迭代,进行一些其他操作,然后在同一作用域中稍后再次对其进行迭代。


1
不符合当前的草案:https://people.mozilla.org/~jorendorff/es6-draft.html#sec-iterator-interface - Felix Kling
2
顺便问一下,for (let x in iterable) 不应该是 for (let x of iterable) 吗? - Felix Kling
是的,你说得对 -- 我会更新代码。 - dvlsg
1
作为给其他读者的提示,我目前正在使用以下解决方法(不一定是解决方案)。通过在生成器函数原型上创建一个@@iterator属性,在访问时自动执行它,返回底层生成器的@@iterator,我可以基本上循环遍历生成器函数。最终结果是我可以按预期迭代生成器函数,使其自动为我创建底层生成器。至于为什么ES6默认情况下不包括此功能,我不确定... - dvlsg
迭代器具有状态,而生成器则没有。您调用生成器以提供迭代器,一旦迭代器被消耗,您再次调用生成器以进行迭代。 - rvighne
当然。我最初的愿望(几年前)是能够像迭代其他可迭代对象(数组、集合、映射等)一样迭代生成器,其中你可以在 for (let val of iterable) {} 中使用生成器。最终,我创建了自己的包装类,在其上定义了 Symbol.iterator,它会在尝试迭代之前自动展开任何包装的生成器(只要不需要任何参数)。这个方法很好用。但是将生成器视为惰性加载的数据序列并不利于性能。 - dvlsg
11个回答

0

没有回到相同状态的机会。

为了让问题更清楚,你必须了解生成器函数的工作原理。

当第一次调用生成器函数时,它将返回一个迭代器(作为其整个主体)。该返回迭代器的初始状态被存储在其变量中。两个非常重要的变量是GeneratorStatus和GeneratorLocation。

还有其他变量,如GeneratorFunction、GeneratorReceiver和Scopes等,这些变量可以忽略以理解此答案。

因此,初始状态将是:

GeneratorStatus:suspended。 GeneratorLocation:1;

现在,要使用迭代器,您应该使用.next()来调用它,从'GeneratorLocation'指向的位置恢复其执行。

现在,生成器将更新其GeneratorLocation值,指向首次产生结果的行号,并且GeneratorLocation将保持不变,直到返回最后一个yield。

对于每次连续的.next调用,生成器将从GeneratorLocation的值恢复其执行,而不是从开头开始。

因此,除非在生成器函数中重复代码,否则无法将其重置为初始状态。最好的解决方案只需使用参数重新创建新的迭代器即可。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接