Javascript ジェネレータにnext()で値を渡した際の挙動メモ

ジェネレータ周りの実装を見ていた時に、`next()`で値を渡した際の挙動がわかりにくかったので、自分用にメモを残します

# ジェネレータとは
定義については、Mozillaのドキュメントを見ていただければと思いますが、ジェネレータとは、
「ジェネレータ関数によって返されたもので、`Array`オブジェクトのようにイテラブルで、またイテレータでもある」
ものとなります。

今回はジェネレータに引数を渡す方法であるGaneratorオブジェクトのインスタンスメソッド`next()`の引数を指定した場合の挙動を把握するためのコード例とその挙動を載せます。

https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Generator/next#value

# 結論： `yield`のところに値が入る。初回の呼び出しでは値が渡せない
ジェネレータは`yield`のところで停止し、`next()`メソッドで次の`yield`のところまで進みます。
`next()`で渡した値は、`yield`のところに入ります。
なので、`yield`で変数の宣言・代入をしていると、値を渡すことができます。
ただし、書いている通り、初回の呼び出しでは値が渡されませんでした。

## メモ１：変数の宣言、代入で指定すると、値を設定できる
下記のコードの例のように、`yield`で変数`value`の値を宣言すると、`next()`の引数を変数`value`に渡すことができます。

注目したいのは、ジェネレータ関数の戻り値`value`は`null`で、変数`value`には引数が入っている点です。`next()`で値を渡さなかった場合は、変数`value`は`undefined`になります。

```js
function* gen() {
  while (true) {
    let value = yield null;
    console.log(value);
  }
}

const g = gen();
g.next(1);
// "{ value: null, done: false }"
g.next(2);
// 2
// "{ value: null, done: false }"
g.next();
// undefined
// "{ value: null, done: false }"
```

下記のように代入にしても同じ結果になります。

```js
function* gen() {
  let value = 5;
  while (true) {
    value = yield null;
    console.log(value);
  }
}

const g = gen();
g.next(1);
// "{ value: null, done: false }"
g.next(2);
// 2
// "{ value: null, done: false }"
g.next();
// undefined
// "{ value: null, done: false }"
```

## メモ2：インクリメントしただけの場合は、値が設定されない
下記のコードの例のように、代入している場合は値を渡すことができます。
が、インクリメントの場合は、値が設定されませんでした。このあたりは同じ挙動です。

```js
function* two() {
  let index = 0;
  while (true) {
    index += yield index;
  }
}

const g2 = two();
console.log(g2.next(1000)); // "{ value: 0, done: false }"
console.log(g2.next(1000)); // "{ value: 1000, done: false }"
console.log(g2.next());     // "{ value: NaN, done: false }"

function* three(){
  let index = 0;
  while (true)
    yield index++;
}

const g3 = three();
console.log(g3.next(1000)); // "{ value: 0, done: false }"
console.log(g3.next(1000)); // "{ value: 1, done: false }"
console.log(g3.next());     // "{ value: 2, done: false }"

function* four(){
  let index = 0;
  while (true)
    yield ++index;
}

const g4 = four();
console.log(g4.next(1000)); // "{ value: 1, done: false }"
console.log(g4.next(1000)); // "{ value: 2, done: false }"
console.log(g4.next());     // "{ value: 3, done: false }"
```

上記なので、インクリメントの場合でも、下記のようにすると渡すことはできます。

```js
function* one() {
  let value = 0;
  while(true) {
    value = yield ++value;
  }
}
var g1 = one();

console.log(g1.next());     // "{ value: 1, done: false }""
console.log(g1.next(1000)); // "{ value: 1001, done: false }"
console.log(g1.next(1000)); // "{ value: 1001, done: false }"
console.log(g1.next());     // "{ value: NaN, done: false }"
```

## メモ３： 初回の`next()`の呼び出しでは、値が渡されない
下記のコードの例のように、初回の`next()`の呼び出しで`"zero0"`を渡していますが、その値は変数`a`に設定されません。
正しく理解できているのか怪しいのですが、現時点の止まっている`yield`のところに値を渡すものと思われ、初回の`next()`の呼び出しでは、値が渡せない仕様です。


```js
function* gfn(){
  let a = yield "first";
  let b = yield "second";
  let c = yield "three";
  yield a + c;
}

var g = gfn();
console.log( g.next("zero0") );   // { value: "first", done: false }
console.log( g.next("first1") );  // { value: "second", done: false }
console.log( g.next("second2") ); // { value: "three", done: false }
console.log( g.next("three3") );  // { value: "first1three3", done: false }
console.log( g.next() );          // { value: undefined, done: true }
```