yieldecmascript-6babeljstraceur

What is the correct (spec-wise) behavior of "yield* undefined" & "yield undefined" in ES6?


While trying to understand how to work with KoaJS, I came to realize that yield* undefined behaves differently between babel & traceur. Babel seem to ignore the statement, while traceur throws an exception. A sample can be seen here: Babel - Traceur, or below:

function* gen() {
  console.log('will \'yield 1\'');
  yield 1;
  console.log('will \'yield undefined\'');
  yield undefined;
  console.log('will \'yield* undefined\'');
  yield* undefined;
  console.log('will \'yield 2\'');
  yield 2;
}

let y = gen();
while(true) {
  try {
    let r = y.next();
    console.log(JSON.stringify(r));
    if(r.done)
      break;
  }
  catch(e) {
    console.log();
    console.log(e);
    console.log();
  };
}

I tried looking it up in the spec and only got more confusion, since the spec for yield doesn't look like yield undefined is supposed to return with {done: false} (No value property), yet that's what happens in both transpilers (also in the sample above). As for yield*, I didn't find an answer why traceur should throw. I didn't try this with v8 (node/iojs) yet.

So the question is, what is the correct / expected behavior in both scenarios?


Solution

  • As you can see in the spec you reference, in the case of yield* expression, expression needs to have a @@iterator property, which needs to be a method; otherwise an exception is thrown. Therefore, yield* undefined should throw an exception because undefined does not have the @@iterator property.

    In the case of yield undefined, undefined should be yielded. This is also what happens. However, in your example you evaluate JSON.stringify({value: undefined, done: false}), which returns '{"done": false}' because there is no such thing as undefined in JSON.