NACの勉強の経過を綴るところ

個人的なコードの勉強

【JS】ジェネレータ関数について

前回のエントリーの続き。
ジェネレーター関数についてもうすこし自分で分かるように噛み砕く。


前回のエントリ
【JS】関数から複数の値を返す - NACの勉強の経過を綴るところ
では、サンプルに書いたスクリプトは配列で返しても同等の処理ができたため、あまりジェネレータ関数を使用するメリットが感じられなかった。
なぜ、わざわざジェネレータ関数を使用しなければいけないのか?
そこを理解するのに、いろいろ調べて時間がかかった。


しかし、以下のようなスクリプトなら、どうか。

function getData(n) {
    let array = [];

    n++;  // 処理1
    array.push(n);
    n++;  // 処理2
    array.push(n);
    n++;  // 処理3
    array.push(n);

    return array;
} 

console.log(getData(3));  // 4, 5, 6

上記の関数は、関数の中の一連の処理を実行し、最後に一回、配列として結果を戻している。
だが、実際にやりたいことは、処理を実行するたびに結果を受け取りたいだけだとすれば、すべての処理を毎回実行するのは非効率だし処理としても重い。構文もエレガントでない。


上記の関数を、ジェネレーター関数を使えば以下のように書き換えることができる。

function* getData(n) {
    let array = [];

    n++;  // 処理1
   yield n;
    n++;  // 処理2
    yield n;
    n++;  // 処理3
    yield n;
} 

var num = getData(3); // ジェネレータ作成

console.log( num .next() ); // { value: 4, done: false }


注目すべき点は、2点。
まず、ジェネレーター関数は、関数内の一連の処理を最初から最後まで実行するわけではなく、上記の例で言えば「処理1」を実行してyieldで戻り値を返した後、処理が一時停止すること。
つまり、複雑な処理を関数に書いて、「とりあえずここまで処理したら値を返す」というようにして、一時休止。
で、改めて指示があれば「その続きから」処理が再開される。


そして、戻り値の受け取り方。
返ってくるのは数値や文字列ではなく、ジェネレーターというオブジェクトである。
上記の例では、「var num = getData(3);」という行の時点では、「num」というジェネレーターが生成されただけで、まだ値は戻ってきていない。
受け皿の準備をしておいて、次の「num.next()」で、「では次の(この場合は最初の)値を呼び出せ」という命令が下り、戻り値を返す「yield」まで処理を実行するのである。


ただ、戻り値の値がよくわからない。
{ value: 4, done: false }
って、なんでこんな値の戻り方をするのか?


これを調べていったら、これが「イテレーター」というものであることがわかった。
また新しい単語出てきた。
どうも、このイテレーターとジェネレーターは、不可分で密接な関係性を持つ考え方で、どちらか片方だけの理解というわけにはいかないようだ。
なので、次回のエントリーでイテレーターについて触れる。