JavaScript プログラミング講座

 

Generator について

 


■ Generator について

 
ECMAScript 6 世代の機能です。
 
■ジェネレーターとは?
 
ジェネレーターは、生成者を意味します。
 
ジェネレーター関数と呼ばれる命令文を記述し、データを順番に生成できます。
 
ジェネレーター関数は、実行を途中で中断し、結果を得る事ができます。
 
中断した場所から、実行を再開する事もできます。
 
Iterator と互換性があり、同じ方法で、順番にデータを列挙できます。
 


 

Generator 関数について

 
 


■ジェネレーター関数について

 
■ジェネレーター関数を宣言する
 
function* 演算子を使用します。
 
ジェネレーター関数を宣言する

// ------------------------------------------------------------
// ジェネレーター関数を宣言する
// ------------------------------------------------------------
function* GeneratorFunc ( argument1 , argument2 ){

	yield 0;
}
 
■ジェネレーター関数を動的に作成する
 
function* リテラルを使用します。
 
ジェネレーター関数を動的に作成する

// ------------------------------------------------------------
// ジェネレーター関数を動的に作成する
// ------------------------------------------------------------
var generator_func = function* ( argument1 , argument2 ){

	yield 0;
};
 

■ Generator オブジェクトを生成する

 
■ Generator オブジェクトを生成する
 
ジェネレーター関数に対して、関数呼び出し演算子 () を使用します。
 
新しい Generator オブジェクトが生成されます。
 
この時点では、ジェネレーター関数はまだ実行されません。
 
引数から、ジェネレーター関数に値を渡す事もできます。
 
■作成例
 
Generator オブジェクトを作成する

// ------------------------------------------------------------
// ジェネレーター関数を宣言する
// ------------------------------------------------------------
function* GeneratorFunc ( argument1 , argument2 ){

	yield 0;
}

// ------------------------------------------------------------
// 新しい Generator オブジェクトを生成する
// ------------------------------------------------------------
var generator0 = GeneratorFunc();
var generator1 = GeneratorFunc( "引数1" , "引数2" );

// ------------------------------------------------------------
// 出力テスト
// ------------------------------------------------------------
console.log(generator0);
console.log(generator1);
 
■ジェネレーター関数を実行するには?
 
Generator オブジェクトの、next() メソッドを使用します。
 

■ yield 文について

 
■ yield を含む構文例
 
yield を含む構文例

function* 関数名 ( 引数 ){

	var 引数 = yield 戻り値;

	var 引数 = yield 戻り値;

	var 引数 = yield 戻り値;

}
 
■関数の実行を中断して結果を得る
 
yield 文まで実行されると、いったん中断されます。
 
ジェネレーターは、suspended な状態に変化します。
 
結果は、next() メソッドの戻り値となります。
 
yield 文による戻り値を確認する

// ------------------------------------------------------------
// ジェネレーター関数
// ------------------------------------------------------------
function* GeneratorFunc(){

	yield "aaa";

	yield "bbb";

	yield "ccc";

}

// ------------------------------------------------------------
// Generator オブジェクトを作成する
// ------------------------------------------------------------
var generator = GeneratorFunc();

// ------------------------------------------------------------
// ジェネレータを順番に実行して結果を得る
// ------------------------------------------------------------
console.log( generator.next() ); // { done:false , value:"aaa" }
console.log( generator.next() ); // { done:false , value:"bbb" }
console.log( generator.next() ); // { done:false , value:"ccc" }
console.log( generator.next() ); // { done:true  , value:undefined }
console.log( generator.next() ); // { done:true  , value:undefined }
 
■引数から値を渡して、関数の実行を再開する
 
もう一度、next() メソッドを呼び出します。
 
引数から、値を渡す事もできます。
 
前回中断した yield 文の位置から、実行は再開されます。
 
yield 文と next() メソッドの相互関係を確認する

// ------------------------------------------------------------
// ジェネレーター関数
// ------------------------------------------------------------
function* GeneratorFunc( args ){
	console.log(args); // "--引数--"

	var result0 = yield "aaa";
	console.log(result0); // "あああ"

	var result1 = yield "bbb";
	console.log(result1); // "いいい"

	var result2 = yield "ccc";
	console.log(result2); // "ううう"
}

// ------------------------------------------------------------
// Generator オブジェクトを作成する
// ------------------------------------------------------------
var generator = GeneratorFunc("--引数--");

// ------------------------------------------------------------
// ジェネレータを順番に実行して結果を得る
// ------------------------------------------------------------
var value0 = generator.next();
var value1 = generator.next("あああ");
var value2 = generator.next("いいい");
var value3 = generator.next("ううう");

// 出力テスト
console.log(value0); // { done:false , value:"aaa" }
console.log(value1); // { done:false , value:"bbb" }
console.log(value2); // { done:false , value:"ccc" }
console.log(value3); // { done:true  , value:undefined }
 
■ yield* 文について
 
戻り値として、Iterable なオブジェクトを指定できます。
 
この場合、引数から値を渡す事はできません。
 
yield* 文による戻り値を確認する

// ------------------------------------------------------------
// ジェネレーター関数
// ------------------------------------------------------------
function* GeneratorFunc(){

	yield* [ "aaa" , "bbb" , "ccc" ];

	yield* "あいう";
}

// ------------------------------------------------------------
// Generator オブジェクトを作成する
// ------------------------------------------------------------
var generator = GeneratorFunc();

// ------------------------------------------------------------
// ジェネレータを順番に実行して結果を得る
// ------------------------------------------------------------
console.log( generator.next() ); // { done:false , value:"aaa" }
console.log( generator.next() ); // { done:false , value:"bbb" }
console.log( generator.next() ); // { done:false , value:"ccc" }
console.log( generator.next() ); // { done:false , value:"あ" }
console.log( generator.next() ); // { done:false , value:"い" }
console.log( generator.next() ); // { done:false , value:"う" }
console.log( generator.next() ); // { done:true  , value:undefined }
console.log( generator.next() ); // { done:true  , value:undefined }
 
■ return 文について
 
ジェネレーターを、closed な状態に変化させます。
 
戻り値を指定できますが、結果は特殊です。
 
for..of 文などを使った場合、列挙に含まれません。
 
return 文による戻り値を確認する

// ------------------------------------------------------------
// ジェネレーター関数
// ------------------------------------------------------------
function* GeneratorFunc(){

	yield "aaa";

	yield "bbb";

	yield "ccc";

	return "ddd";
}

// ------------------------------------------------------------
// Generator オブジェクトを作成する
// ------------------------------------------------------------
var generator0 = GeneratorFunc();
var generator1 = GeneratorFunc();

// ------------------------------------------------------------
// ジェネレータを順番に実行して結果を得る
// ------------------------------------------------------------
console.log( generator0.next() ); // { done:false , value:"aaa" }
console.log( generator0.next() ); // { done:false , value:"bbb" }
console.log( generator0.next() ); // { done:false , value:"ccc" }
console.log( generator0.next() ); // { done:true  , value:"ddd" }
console.log( generator0.next() ); // { done:true  , value:undefined }
console.log( generator0.next() ); // { done:true  , value:undefined }

// ------------------------------------------------------------
// for..of 文を使って、データを列挙する
// ------------------------------------------------------------
var value;
for(value of generator1){
	console.log( value );
}
 


 

Generator オブジェクトについて

 
 


■ジェネレーターを実行して結果を得る

 
■ ジェネレーターを実行して結果を得る
 
next() メソッドを使用します。
 
next() メソッドを、何度も呼び出す事で、値情報を順番に取り出せます。
 
Generator.next( value ) :IteratorResult
第01引数(略可)*中断した yield 文に渡す値を指定する(suspended の状態である場合)
戻り値 IteratorResult新しい IteratorResult オブジェクトが得られる。
 
■IteratorResult オブジェクトについて
 
プロパティ 解説
done Boolean 列挙が最後尾まで完了したなら true
value * 今回の値情報を取得する
 
■ yield 文との連携について
 
詳しくは、こちらで解説しています。
 

■ジェネレーターを閉じて結果を得る

 
return() メソッドを使用します。
 
ジェネレーターを、closed な状態に変化させます。
 
Generator.return( value ) :IteratorResult
第01引数(略可)*最後の値情報を指定する
戻り値 IteratorResult新しい IteratorResult オブジェクトが得られる。
 
■使用例
 
return() メソッドの動作を確認する

// ------------------------------------------------------------
// ジェネレーター関数
// ------------------------------------------------------------
function* GeneratorFunc(){

	yield "aaa";

	yield "bbb";

	yield "ccc";

}

// ------------------------------------------------------------
// Generator オブジェクトを作成する
// ------------------------------------------------------------
var generator = GeneratorFunc();

// ------------------------------------------------------------
// ジェネレータを順番に実行して結果を得る
// ------------------------------------------------------------
console.log( generator.next() ); // { done:false , value:"aaa" }
console.log( generator.next() ); // { done:false , value:"bbb" }

// ------------------------------------------------------------
// ジェネレータを閉じる
// ------------------------------------------------------------
var result = generator.return("ddd");

// 出力テスト
console.log( result ); // { done:true  , value:undefined }

// ------------------------------------------------------------
// 閉じられたか確認する
// ------------------------------------------------------------
console.log( generator.next() ); // { done:true  , value:undefined }
console.log( generator.next() ); // { done:true  , value:undefined }
 

■ジェネレーターにエラーをスローする

 
throw() メソッドを使用します。
 
ジェネレーターを、closed な状態に変化させます。
 
Generator.throw( exception ) :Void
第01引数(略可)ErrorError オブジェクトなどを指定
戻り値 Voidなし
 
■使用例
 
throw() メソッドの動作を確認する

// ------------------------------------------------------------
// ジェネレーター関数
// ------------------------------------------------------------
function* GeneratorFunc(){

	yield "aaa";

	yield "bbb";

	yield "ccc";

}

// ------------------------------------------------------------
// Generator オブジェクトを作成する
// ------------------------------------------------------------
var generator = GeneratorFunc();

// ------------------------------------------------------------
// ジェネレータを順番に実行して結果を得る
// ------------------------------------------------------------
console.log( generator.next() ); // { done:false , value:"aaa" }
console.log( generator.next() ); // { done:false , value:"bbb" }

// ------------------------------------------------------------
// ジェネレータにエラーをスローする
// ------------------------------------------------------------
try{
	// Error オブジェクトを作成
	var error_obj = new Error("ddd");

	// 例外エラーを投げる
	generator.throw(error_obj);

}catch(e){
	console.log(e); // "ddd"
}

// ------------------------------------------------------------
// 閉じられたか確認する
// ------------------------------------------------------------
console.log( generator.next() ); // { done:true  , value:undefined }
console.log( generator.next() ); // { done:true  , value:undefined }
 

■Generator を使ってデータを列挙する

 
こちらで解説しています。
 
Generator は、Iterator の仕様を満たします。
 
■値情報を順番に列挙する例(Iterator オブジェクト)
 
while 文を使って、値情報を順番に取得する

// ------------------------------------------------------------
// ジェネレーター関数
// ------------------------------------------------------------
function* GeneratorFunc(){
	yield* ["aaa" , "bbb" , "ccc" , "ddd" , "eee"];
}

// ------------------------------------------------------------
// Generator オブジェクトを作成する
// ------------------------------------------------------------
var generator = GeneratorFunc();

// ------------------------------------------------------------
// 値情報を順番に列挙する
// ------------------------------------------------------------
var result = generator.next();
while(!(result.done)){
	console.log( result.value );
	result = generator.next();
}
 
■値情報を順番に列挙する例(for..of 文)
 
for..of 文を使って、値情報を順番に取得する

// ------------------------------------------------------------
// ジェネレーター関数
// ------------------------------------------------------------
function* GeneratorFunc(){
	yield* ["aaa" , "bbb" , "ccc" , "ddd" , "eee"];
}

// ------------------------------------------------------------
// Generator オブジェクトを作成する
// ------------------------------------------------------------
var generator = GeneratorFunc();

// ------------------------------------------------------------
// 値情報を順番に列挙する(Iterable なオブジェクトを指定)
// ------------------------------------------------------------
var value;
for(value of generator){
	console.log( value );
}
 
■すべての値情報をまとめて取得する例(Map オブジェクトを取得)
 
ジェネレーターから、Map オブジェクトを生成する

// ------------------------------------------------------------
// ジェネレーター関数(オブジェクトから [ "キー" , 値 ] を列挙)
// ------------------------------------------------------------
function* Object_Entries(obj){
	var key;
	for(key in obj){
		var value = obj[key];
		yield [ key , value ];
	}
};

// ------------------------------------------------------------
// 適当なオブジェクトを用意
// ------------------------------------------------------------
var dictionary = {
	"aaa":"あ",
	"bbb":"い",
	"ccc":"う",
	"ddd":"え",
	"eee":"お"
};

// ------------------------------------------------------------
// ジェネレーターを生成
// ------------------------------------------------------------
var generator = Object_Entries(dictionary);

// ------------------------------------------------------------
// ジェネレーターから、Map オブジェクトを生成する
// ------------------------------------------------------------
var map = new Map(generator);

// 出力テスト
console.log(map); // { "aaa":"あ" , "bbb":"い" , "ccc":"う" , "ddd":"え" , "eee":"お" }