Javascript ES6生成器。他们到底是什么人?

时间:2016-05-07 22:43:09

标签: javascript

所以我看到下面的链接,我问自己:究竟是什么意思?它真正实现了什么,目的是什么?

对于像我这样的初学者来说,这个例子可能有点过于复杂,但老实说我不明白。

http://es6-features.org/#GeneratorFunctionIteratorProtocol

上述来源的示例:

let fibonacci = { * [Symbol.iterator]() {
        let pre = 0,
            cur = 1
        for (;;) {
            [pre, cur] = [cur, pre + cur] yield cur
        }
    }
}
for (let n of fibonacci) {
    if (n > 1000) break console.log(n)
}

1 个答案:

答案 0 :(得分:4)

  

但最重要的问题是:它有什么好处?

某些对象具有自然而明显的迭代方法,例如使用数组或字符串,您可以使用其索引按顺序访问每个元素或字符。但是其他对象更复杂,JavaScript无法猜测您可能想要迭代它们的属性。通过在对象上实现迭代器协议,您可以在任何对象上定义自己的迭代行为,但是以其他代码使用标准for of循环语法或使用它来访问它迭代器.next() method。您甚至可以定义多个迭代器方法,以便可以在不同的序列中迭代同一个对象。或者,如在您的示例中,您可以实现一个不迭代其自身属性的对象,它生成一个无限的值列表 - 但是当被要求下一个值时,它会一次生成一个。

所以,让我们退后一步,看看一个更常见的结构,比如一个固定长度的值数组:

var colours = ["Red", "Yellow", "Green", "Brown", "Blue"];

使用所有值执行某些操作的旧式方法是一个简单的for循环:

for (var i = 0; i < colours.length; i++)
  console.log(colours[i]);

但是新的替代for of语法可以让您获得相同的效果,而无需担心初始化和递增i变量或测试数组长度:

for (let colour of colours)
   console.log(colour);

回到你的fibonacci例子,Fibonacci序列是无限的,但是你不能创建一个无限长度的数组,用无限的值列表填充它,然后迭代它。但是使用ES6生成器,您可以创建一个fibonacci对象,您可以迭代它,就像它是一个数组一样:

for (let n of fibonacci) {
    if (n > 1000) break;
    console.log(n)
}

循环并不关心fibonacci是如何实现的,它只知道它是一个可迭代的对象。循环可以将其视为通用列表,注意因为它的行为类似于无限长度列表,循环需要ifbreak,以便它在适当的任何限制下停止。如果列表是有限的,那么你不需要if,循环将在最后一个项目处理后自然结束。

现在看一下fibonacci的实现,你会注意到它包含了一个看似无限循环的东西:

for (;;) {...}

这是老派的for语法,但没有结束条件,所以它会永远持续下去。除了在循环内你有一个yield语句:

    yield cur

...返回值cur,但与在函数中使用return语句不同,不会结束函数,它只是“暂停”它,使用迭代器将控制返回到代码,但保持所有变量的最新状态,并在以后要求下一个值时准备好使用。如果你的其他代码从未要求下一个值,那就没关系,因为你还没有占用大量的内存来跟踪到目前为止序列中的所有数字 - 没有必要提前计算序列,代码只需知道当前值和先前值是什么,以便计算下一个值。

当然,即使在ES6之前,您也可以在对象上实现某种迭代方法,并使用一种以某种方式保持状态的函数,以便在每次后续调用中它继续停止。并不困难,但是使用该对象的代码需要知道该方法是否被调用.next(),或getNext(),或者其他什么,并且您需要显式调用该方法并管理自己的循环。新的ES6生成器概念允许您以对调用代码标准且透明的方式实现这些内容,因此您只需将它们插入到简单的for of循环中即可。

主题很复杂,还有其他用途(比如其他答案中提到的异步事件),但希望这有点帮助。