JavaScript の ジェネレータ を極める！

*ECMAScript 6*（2015年6月に公開され、今もなお比較的新しい *JavaScript*）の大目玉である <font color=#c70>イテレータ</font> と <font color=#0c7>ジェネレータ</font>。なかなかに複雑で巨大な仕組みになっていてややこしいです。
そこで今回は <font color=#0c7>ジェネレータ</font> を、順を追って理解できるように解説したいと思います。

* [Qiita: JavaScript の イテレータ を極める！](http://qiita.com/kura07/items/cf168a7ea20e8c2554c6) ←こちらから読むのがオススメです
* **[Qiita: JavaScript の ジェネレータ を極める！]()（この記事）**

また、実用的なサンプルを「[3. 実用サンプル][3.]」に示しました。
初めにこちらを見て、何ができるのかを知ってから読み始めるのもオススメです。

（2017年3月現在、オープンなページでの使用はまだ避けたほうがいいかもしれませんが、実装は確実に進んでいます。[ECMAScript 6 compatibility table](http://kangax.github.io/compat-table/es6/#test-generators)）

# 1. <font color=#0c7>ジェネレータ</font>、ジェネレータ関数 とは

**<font color=#0c7>ジェネレータ</font> は、<font color=#c70>イテレータ</font> を強力にサポート** するものです。

例えば、1～20の数を順番に取り出す for-of文 は、以下のように書くことができます。
（<font color=#0c7>ジェネレータ</font> は使っていません。）

```js:1～20の数を順番に取り出すfor-of文
var ary = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20];
for(var num of ary) console.log(num);
/*
  1
  2
  3
  ...
  20
*/
```

この書き方でも十分に分かりやすいです。
しかし、取り出す数が1ずつ増えていくという処理を、関数でスマートに書きたいものです。
そこで、**<font color=#0c7>ジェネレータ</font> を使えばもっとスマートに書くことができます**。

```js:ジェネレータを使って1～20の数を順番に取り出すfor-of文
function* gfn(from, to){ while(from <= to) yield from++; }
var g = gfn(1, 20);
for(var num of g) console.log(num);
/*
  1
  2
  3
  ...
  20
*/
```

このような簡単な例だけでなく、2倍ずつにして順番に取り出したり、フィボナッチ数列を順番に取り出したりすることもできます。
このように、<font color=#0c7>ジェネレータ</font> は <font color=#c70>イテレータ</font> を強力にサポートすることができるのです。

ここにおいて、

* **ジェネレータ関数 は、`function* gfn(from, to){ while(from <= to) yield from++; }`**、
* **<font color=#0c7>ジェネレータ</font> は、`gfn(1, 20)` のように ジェネレータ関数 から得ることのできるオブジェクト**

を、それぞれ指す用語です。

<font color=#0c7>ジェネレータ</font> は、イテラブル であり、なおかつ <font color=#c70>イテレータ</font> でもあります。
つまり、[Qiita: JavaScript の イテレータ を極める！](http://qiita.com/kura07/items/cf168a7ea20e8c2554c6) の [2.6.2. イテラブルなオブジェクト の利用法](http://qiita.com/kura07/items/cf168a7ea20e8c2554c6#262-%E3%82%A4%E3%83%86%E3%83%A9%E3%83%96%E3%83%AB%E3%81%AA%E3%82%AA%E3%83%96%E3%82%B8%E3%82%A7%E3%82%AF%E3%83%88-%E3%81%AE%E5%88%A9%E7%94%A8%E6%B3%95) で紹介したような利用法ができます。

# 2. <font color=#0c7>ジェネレータ</font> を使う

## 2.1. ジェネレータ関数 の書き方、使い方

便利な ジェネレータ関数 の書き方を学びましょう。といっても、普通の関数の書き方とほとんど違いはありません。
**普通の関数と違う点は、以下のたった2点だけ**です。

* ジェネレータ関数 は、`function* gfn(){}` または `var gfn = function*(){};` のように、**`function` のあとに `*` を記述する必要がある**
* ジェネレータ関数 では、**`yield` 及び `yield*` を使うことができる**

例として簡単な ジェネレータ関数 を見てみましょう。

```js:ジェネレータ関数
function* gfn(){
	var a = yield 0;
	yield* [1, a, 5];
}
```

これで ジェネレータ関数は完成しました。
ジェネレータ関数 から <font color=#0c7>ジェネレータ</font> を作るには、単に `gfn()` のように記述すればオッケーです。
ただし、**`gfn()` の時点では関数の中身が実行されないことは要注意です**。
関数の中身は、`gfn()` で生成された <font color=#0c7>ジェネレータ</font> から `.next()` で値を取り出す時点で実行されます。

```js:ジェネレータ関数からジェネレータを作って実行する
function* gfn(){
	var a = yield 0;
	yield* [1, a, 5];
}

var g = gfn(); // ジェネレータを作った。この時点ではまだ関数の中身は実行されない

// g.next() を実行すると、関数の中身が順番に実行される
console.log( g.next() ); //  { value: 0, done: false }
console.log( g.next(3) ); // { value: 1, done: false }
console.log( g.next() ); //  { value: 3, done: false }
console.log( g.next() ); //  { value: 5, done: false }
console.log( g.next() ); //  { value: undefined, done: true }
```

それでは、もっと簡単なコードを例にして、ジェネレータ関数 の仕組みを見てみましょう。

## 2.2. `yield`

```js:yield式
function* gfn(n){
	n++;
	yield n;
	n *= 2;
	yield n;
	n = 0;
	yield n;
}

var g = gfn(10); // ジェネレータを作った

console.log( g.next() ); // { value: 11, done: false }
// n++; が実行された後、yield n; によって n の値が返された。
```

<font color=#0c7>ジェネレータ</font> を作って **`.next()` を実行すると、最初の `yield` が出てくるまで関数が実行されます**。
`yield` まで関数が実行されると、**関数の実行はいったん停止し、イテレータリザルトとして値が返されます**。

**再び `.next()` を実行すると、いったん停止した位置から再び関数が再開され、次の `yield` まで実行されます**。
最後まで関数が実行されると、イテレータリザルトの `.done` が `true` になり、関数の実行が終了します。

```js:yield式
function* gfn(n){
	n++;
	yield n;
	n *= 2;
	yield n;
	n = 0;
	yield n;
}

var g = gfn(10); // ジェネレータを作った

console.log( g.next() ); // { value: 11, done: false }
// n++; が実行された後、yield n; によって n の値が返された。

console.log( g.next() ); // { value: 22, done: false }
// n *= 2; が実行された後、yield n; によって n の値が返された。

console.log( g.next() ); // { value: 0, done: false }
// n = 0; が実行された後、yield n; によって n の値が返された。

console.log( g.next() ); // { value: undefined, done: true }
// 関数の実行が終了したので、.done が true になった。
```

## 2.3. ジェネレータに値を渡す

**`.next(val)` のように値を渡してやることで、ジェネレータに値を渡すことができます**。

```js:ジェネレータに値を渡す
function* gfn(){
	var a = yield "first";
	var b = yield "second";
	yield a + b;
}

var g = gfn();

console.log( g.next() ); // { value: "first", done: false }

console.log( g.next(3) ); // { value: "second", done: false }
// yield "first" の部分が 3 に置き換えられる

console.log( g.next(5) ); // { value: 8, done: false }
// yield "second" の部分が 5 に置き換えられる

console.log( g.next() ); // { value: undefined, done: true }
```

`g.next(3)` などを実行することで、ジェネレータ関数の中身に値を渡しています。
渡した値は、直前にいったん停止した `yield` と置き換えられたように渡されます。

## 2.4. `yield*`

`yield` のほかに `yield*` という便利な式があります。
`yield*` には イテラブルなオブジェクト を与えます。
すると、**イテラブルなオブジェクト から順番に値を取り出し、それぞれの値に対して `yield` を行ってくれます**。

```js:yield*式
function* gfn(){
	yield* [1, 3, 5];
}

var g = gfn();

console.log( g.next() ); // { value: 1, done: false }
console.log( g.next() ); // { value: 3, done: false }
console.log( g.next() ); // { value: 5, done: false }
console.log( g.next() ); // { value: undefined, done: true }
```

```js:yield*式
function* gfn(){
	yield* "ひよこ";
}

var g = gfn();

console.log( g.next() ); // { value: "ひ", done: false }
console.log( g.next() ); // { value: "よ", done: false }
console.log( g.next() ); // { value: "こ", done: false }
console.log( g.next() ); // { value: undefined, done: true }
```

つまり、`for(var v of iterable) yield v;` と同様の処理を行っているというわけです。

## 2.5. 簡単なサンプル

全て、ジェネレータが イテラブルなオブジェクト であることを利用したサンプルです。

```js:ジェネレータを利用する
function* gfn(){
	yield 1;
	yield* [2, 1, 2];
}

for(var num of gfn()) console.log(num);
/*
  1
  2
  1
  2
*/

console.log( [...gfn()] ); // [1, 2, 1, 2]

console.log( Math.max(...gfn()) ); // 2

var [a, b, c, d] = gfn();
console.log(a, b, c, d); // 1, 2, 1, 2

console.log( new Set(gfn()) ); // Set {1, 2}
```

## 2.6. <font color=#0c7>ジェネレータ</font> のもう一つの利用法

今まで見てきた <font color=#0c7>ジェネレータ</font> は、**<font color=#c70>イテレータ</font> として利用する**ことに重点を置いてきました。

しかし、見方を変えれば、<font color=#0c7>ジェネレータ</font> はもう一つの使い方ができます。
それは、**自由に途中でいったん停止できる関数** という見方です。

```js:ページをクリックするたびにひとつずつアラートを出す
function* gfn(){
	alert("こんにちは！"); yield;
	alert("良い天気ですね。"); yield;
	alert("さようなら！");
}
var g = gfn();
document.onclick = function(){ g.next(); }; // ページをクリックするたびに g.next(); を実行する
```

**コード中の `yield` の時点で、関数の実行をいったん停止することができる** と考えると、分かりやすいかと思います。
これは、非同期処理をする際に、かなりの力を発揮します。

# 3. 実用サンプル

<font color=#0c7>ジェネレータ</font> で説明することは以上ですが、実際のサンプルがないと、どのようにつかえるかのイメージがつきにくいと思います。
いくつかサンプルを挙げますので、参考にしてください。

```js:1000以下のフィボナッチ数を列挙する
function* fibonacci(){
	var a = 0, b = 1, temp;
	while(true){
		temp = a + b;
		a = b; b = temp;
		yield a;
	}
}

var g = fibonacci();
for(var num of g){
	if(num > 1000) break;
	console.log(num);
}
/*
  1
  2
  3
  5
  8
  13
  21
  34
  55
  89
  144
  233
  377
  610
  987
*/
```

```js:ランダムな自然数の配列を作る
function* randomIntArray(max, len){
	for(var i=0;i<len;i++) yield Math.floor(Math.random() * max) + 1;
}

console.log( [...randomIntArray(2, 10)] ); // 例：[1, 2, 1, 1, 1, 2, 2, 2, 1, 2]
console.log( [...randomIntArray(6, 4)] ); // 例：[1, 6, 2, 4]
```

```js:組み合わせを順番に取り出す
function* combination(ary, len){
	yield* (function* gfn(a, ary){
		if(a.length < len){
			for(var i=0;i<ary.length-len+a.length+1;i++){
				yield* gfn(a.concat(ary[i]), ary.slice(i+1));
			}
		}
		else yield a;
	})([], ary);
}

for(v of combination([1,2,3], 2)) console.log(v);
/*
  [1, 2]
  [1, 3]
  [2, 3]
*/

for(v of combination(["A", "B", "C", "D", "E"], 3)) console.log(v.join(""));
/*
  ABC
  ABD
  ABE
  ACD
  ACE
  ADE
  BCD
  BCE
  BDE
  CDE
*/
```

```js:非同期処理を分かりやすく書く
function easyAsync(gfn){
	var g = gfn();
	(function ok(value){
		var result = g.next(value);
		if(!result.done) result.value(ok);
	})();
}

easyAsync(function*(){
	alert("こんにちは！");
	yield function(ok){
		setTimeout(ok, 3000);
	};
	alert("3秒たちました！");
	yield function(ok){
		document.onclick = ok;
	};
	document.onclick = null;
	alert("ページをクリックしました！");
	var sourse = yield function(ok){
		var xhr = new XMLHttpRequest();
		xhr.open("GET", location.href, true);
		xhr.send(null);
		xhr.onload = function(){ ok(xhr.responseText); };
	};
	alert("このページのソースは" + sourse.length + "文字です！");
});
```


# 4. 参考
[ECMAScript 2015 Language Specification &ndash; ECMA-262 6th Edition](http://www.ecma-international.org/ecma-262/6.0/)
[Iterators and generators - JavaScript | MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Iterators_and_Generators)
[ジェネレータについて - JS.next](http://js-next.hatenablog.com/entry/2014/08/07/174147)
[ECMAScript 6 compatibility table](https://kangax.github.io/compat-table/es6/)


[1.]: #1-%E3%82%B8%E3%82%A7%E3%83%8D%E3%83%AC%E3%83%BC%E3%82%BF%E3%82%B8%E3%82%A7%E3%83%8D%E3%83%AC%E3%83%BC%E3%82%BF%E9%96%A2%E6%95%B0-%E3%81%A8%E3%81%AF "1. ジェネレータ、ジェネレータ関数 とは"
[2.]: #2-%E3%82%B8%E3%82%A7%E3%83%8D%E3%83%AC%E3%83%BC%E3%82%BF-%E3%82%92%E4%BD%BF%E3%81%86 "2. ジェネレータ を使う"
[2.1.]: #21-%E3%82%B8%E3%82%A7%E3%83%8D%E3%83%AC%E3%83%BC%E3%82%BF%E9%96%A2%E6%95%B0-%E3%81%AE%E6%9B%B8%E3%81%8D%E6%96%B9%E4%BD%BF%E3%81%84%E6%96%B9 "2.1. ジェネレータ関数 の書き方、使い方"
[2.2.]: #22-yield "2.2. yield"
[2.3.]: #23-%E3%82%B8%E3%82%A7%E3%83%8D%E3%83%AC%E3%83%BC%E3%82%BF%E3%81%AB%E5%80%A4%E3%82%92%E6%B8%A1%E3%81%99 "2.3. ジェネレータに値を渡す"
[2.4.]: #24-yield "2.4. yield*"
[2.5.]: #25-%E7%B0%A1%E5%8D%98%E3%81%AA%E3%82%B5%E3%83%B3%E3%83%97%E3%83%AB "2.5. 簡単なサンプル"
[2.6.]: #26-%E3%82%B8%E3%82%A7%E3%83%8D%E3%83%AC%E3%83%BC%E3%82%BF-%E3%81%AE%E3%82%82%E3%81%86%E4%B8%80%E3%81%A4%E3%81%AE%E5%88%A9%E7%94%A8%E6%B3%95 "2.6. ジェネレータ のもう一つの利用法"
[3.]: #3-%E5%AE%9F%E7%94%A8%E3%82%B5%E3%83%B3%E3%83%97%E3%83%AB "3. 実用サンプル"
[4.]: #4-%E5%8F%82%E8%80%83 "4. 参考"