HTML5テクニカルノート
TypeScript: イテレータとジェネレータ
- ID: FN1805003
- Technique: HTML5 / ECMAScript 2015
- Package: TypeScript 2.8
イテレータとジェネレータは、データから項目を順に取り出して反復処理するために採り入れられた仕組みです。本稿は、公式Handbook「Iterators and Generators」にもとづき、解説とコード例を大きく改めました。
01 反復可能オブジェクト
反復処理のふるまいが定められたオブジェクトを、反復可能(iterable)オブジェクトと呼びます。反復可能オブジェクトは、Symbol.iteratorプロパティを備えていなければなりません。Array、Map、Set、String、Int32Array、Uint32Arrayなどの組み込み型には、あらかじめ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..inもfor..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でcompilerOptionsのtargetをes6にしなければなりません。
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におけるcompilerOptionsのtarget)が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.