问题
For ES6 generators, why does the author of this blog post say:
from: http://davidwalsh.name/es6-generators
"The first next(..) call, we don't send in anything. Why? Because there's no yield expression to receive what we pass in."
Doesn't the first it.next()
call (yield (x + 1))
?
function *foo(x) {
var y = 2 * (yield (x + 1));
var z = yield (y / 3);
return (x + y + z);
}
var it = foo( 5 );
// note: not sending anything into `next()` here
console.log( it.next() ); // { value:6, done:false }
console.log( it.next( 12 ) ); // { value:8, done:false }
console.log( it.next( 13 ) ); // { value:42, done:true }
You can see that we can still pass in parameters (x in our example) with the initial foo( 5 ) iterator-instantiation call, just like with normal functions.
The first next(..) call, we don't send in anything. Why? Because there's no yield expression to receive what we pass in.
回答1:
The first it.next()
corresponds to the yield(x + 1)
, which results in 6 as expected. The 12 in the next call to it.next(12)
sets the value of that first yield to 12, so y
is set to double that, or 24 and the iterator results in the value (y / 3)
, which is 8. The final call to it.next(13)
sets the value of the second yield to 13, which is set to z
, and receives the value of the return
, which is 5 + 24 + 13.
Granted, it is a little bit confusing, due to the syntax
z = yield(y / 3)
which somehow looks like one is assigning the value of something to do with y / 3
to z
. That's not the case. y / 3
is the value being yielded to serve as the value of the iterator, whereas z
is being assigned to the value passed in by the following it.next()
call, something entirely different! It may be slightly helpful to omit the parentheses and write this as
var y = 2 * yield x + 1;
var z = yield y / 3;
keeping in mind that yield
is a statement, not a function call.
As for the error you mention, in traceur for example it is "Sent value to newborn generator". It makes sense when you think about it. The value send as a parameter to it.next()
becomes the value of the most recent yield in the generator. On the first call to it.next()
, there is no most recent yield in the generator, so there's nothing to take on the value being passed, hence the error.
Don't confuse passing parameters to the generator (x
in your case), which merely provides a way to configure or initialize the generator, with passing parameters to it.next()
, which serve as the value of the most recent yield
in the generator.
It may be helpful to consider how you would write the equivalent hand-rolled generator (simplified to just return the next value instead of {value, done}
, and throwing when the generator is out of gas):
function foo(x) {
var y, z, step = 0;
return function next(val) {
switch (step++) {
case 0: return x + 1; break;
case 1: y = 2 * val; return y / 3; break;
case 2: z = val; return x + y + z; break;
default: throw "generator finished";
}
};
}
Then:
iterator = foo(5);
iterator(); // 6
iterator(12); // 8
iterator(13); // 42
来源:https://stackoverflow.com/questions/26695346/es6-generators-example-where-there-is-no-yield-expression-for-the-first-next