サイトトップ

Director Flash 書籍 業務内容 プロフィール

HTML5テクニカルノート

TypeScript: イテレータとジェネレータ


イテレータとジェネレータは、データから項目を順に取り出して反復処理するために採り入れられた仕組みです。本稿は、公式Handbook「Iterators and Generators」にもとづき、解説とコード例を大きく改めました。

01 反復可能オブジェクト

反復処理のふるまいが定められたオブジェクトを、反復可能(iterable)オブジェクトと呼びます。反復可能オブジェクトは、Symbol.iteratorプロパティを備えていなければなりません。ArrayMapSetStringInt32ArrayUint32Arrayなどの組み込み型には、あらかじめSymbol.iteratorプロパティが与えられています。 オブジェクトのSymbol.iterator関数が、反復処理する値をデータから順に返すのです。

02 for...of文

反復可能オブジェクトは、for...ofのループ構造で内部の値を繰り返し処理できます。そのループ処理の中で、Symbol.iteratorプロパティの関数が内部的に呼び出されるのです。


let array = [1, "string", false];
for (let entry of array) {
	console.log(entry);
}
/* コンソール出力
1
string
false
*/

03 文for..ofとfor..inの違い

for..infor..ofと同じく、配列を繰り返し処理できます。けれど、取り出す値が異なるのです。for..in文がオブジェクトのキー(インデックス)を得るのに対して、for..of文からはインデックスに納められた値が取り出されます。


let array = [4, 5, 6];
for (let i in array) {
	console.log(i);
}
/* コンソール出力
0
1
2
*/
for (let i of array) {
	console.log(i);
}
/* コンソール出力
4
5
6
*/

for..of文で配列要素の値だけでなくインデックスも得たい場合には、Array.prototype.entries()メソッド分割代入を用います。


for (let [i, value] of array.entries()) {
	console.log(i, value);
}
/* コンソール出力
0 4
1 5
2 6
*/

ただし、Array.prototype.entries()メソッドを使うには、tsconfig.jsonでcompilerOptionstargetes6にしなければなりません。

tsconfig.json

{
	"compilerOptions": {
		"target": "es6",

	}
}

for..in文は、オブジェクトからプロパティの識別子(キー)を順に取り出せます。けれど、for..of文で繰り返し処理できるのは、反復可能オブジェクトだけです。


let object =  {a: 1, b: 2, c: 3};
for (let i in object) {
	console.log(i);
}
/* コンソール出力
a
b
c
*/
/*
for (let i of object) {  // コンパイルエラー
	console.log(i);
}
*/

反復可能オブジェクトには、たとえばSetオブジェクトがあります。Setは、一意の値が納められるオブジェクトです。値は、for..of文で取り出せます。繰り返し処理が内部的に呼び出すSymbol.iteratorプロパティにより、値が順に得られるのです。Setオブジェクトにコンストラクタやメソッドで加えた値は、for...in文では取り出せません。ただし、オブジェクトのプロパティとして与えたキー(識別子)は、for...inループで参照できます。


let pets = new Set(['Cat', 'Dog', 'Hamster']);
pets['species'] = 'mammals';
for (let pet in pets) {
	console.log(pet);
}
/* コンソール出力
species
*/
for (let pet of pets) {
	console.log(pet);
}
/* コンソール出力
Cat
Dog
Hamster
*/

04 ターゲットのECMAScriptと生成されるコード

反復可能オブジェクト(Symbol.iteratorプロパティ)とfor...of文は、ECMAScript 2015の構文です。けれど、コンパイラのターゲット(tsconfig.jsonにおけるcompilerOptionstarget)がECMAScript 5(es5)であっても、配列はfor...ofループで処理できます。


let numbers = [1, 2, 3];
for (let num of numbers) {  // コンパイルエラーなし
	console.log(num);
}

それは、配列についてはfor...of文が、forループでJavaScriptコードにコンパイルされるからです。

JavaScriptコード

var numbers = [1, 2, 3];
for (var _i = 0, numbers_1 = numbers; _i < numbers_1.length; _i++) {
    var num = numbers_1[_i];
    console.log(num);
}

ターゲットをECMAScript 2015(es6)にすると、反復可能オブジェクトとしてfor...of文で処理するようにコンパイルされます。

JavaScriptコード

let numbers = [1, 2, 3];
for (let num of numbers) {
    console.log(num);
}


作成者: 野中文雄
作成日: 2018年5月7日


Copyright © 2001-2018 Fumio Nonaka.  All rights reserved.