Reputation: 3222
So I see the link below and I ask myself: what exactly is the point of this? What does it really accomplish and for what purpose?
Maybe the example is a bit too complicated for starter like me but I honestly dont get it.
http://es6-features.org/#GeneratorFunctionIteratorProtocol
Example from source above:
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)
}
Upvotes: 1
Views: 91
Reputation: 150010
The big question is though: what is it good for?
Some objects have a natural and obvious method of iteration, for example with an array or string you can access each element or character in order using its index. But other objects are more complicated, and JavaScript can't guess how you might want to iterate through their properties. By implementing the iterator protocol on an object, you can define your own iteration behaviour on any object, but in such a way that other code an access it using standard for of
loop syntax, or using the iterator .next()
method. You can even define more than one iterator method such that you can iterate over the same object in different sequences. Or, as in your example, you can implement an object that isn't iterating over its own properties, it is generating an infinite list of values - but one at a time when asked for the next.
So, let's take a step back, and look at a more common structure like a fixed-length array of values:
var colours = ["Red", "Yellow", "Green", "Brown", "Blue"];
The old-school way to do something with all the values is a simple for
loop:
for (var i = 0; i < colours.length; i++)
console.log(colours[i]);
But the new alternative for of
syntax lets you get the same effect without having to worry about initialising and incrementing the i
variable or testing the array length:
for (let colour of colours)
console.log(colour);
So coming back to your fibonacci
example, the Fibonacci Sequence is infinite, but you can't create an array of infinite length, fill it with an infinite list of values, and then iterate over it. But using ES6 generators you can create a fibonacci
object that you can iterate over almost as if it were an array:
for (let n of fibonacci) {
if (n > 1000) break;
console.log(n)
}
The loop doesn't care how fibonacci
is implemented, all it knows is that it is an iterable object. The loop can treat it as a generic list, noting that because it is acting like an infinite-length list the loop needs that if
and break
so that it stops at whatever limit seems appropriate. If the list were finite then you wouldn't need that if
, the loop would end naturally after the last item is processed.
So looking now at the implementation of fibonacci
, you'll notice that it contains what looks like an infinite loop:
for (;;) {...}
That is the old-school for
syntax, but with no end condition, so it just goes on forever. Except that within the loop you have a yield
statement:
yield cur
...which returns the value cur
, but unlike using a return
statement in a function it doesn't end the function, it just "pauses" it, yielding control back to the code using the iterator, but keeping all the variables current and ready for use later when it is asked for the next value. If your other code never asks for the next value then that's OK, because you haven't tied up a ton of memory keeping track of all of the numbers in the sequence so far - there is no need to calculate the sequence in advance, the code only needs to know what the current and previous values are in order to calculate the next value.
Of course even pre-ES6 you could implement some kind of iteration method on your objects, with a function that keeps state somehow so that on each subsequent call it continues where it left off. Not difficult, but then the code that uses that object needs to know if the method is called .next()
, or getNext()
, or whatever, and you'd need to call that method explicitly and manage your own loop. The new ES6 generator concept lets you implement these things in a way that is standard and transparent to the calling code, so you can just plug them into a plain for of
loop.
The topic is complicated, and there are other uses (like the async thing mentioned in the other answer), but hopefully this helped a bit.
Upvotes: 4