このページの2つのバージョン間の差分を表示します。
両方とも前のリビジョン 前のリビジョン 次のリビジョン | 前のリビジョン | ||
js:iteration_protocols [2021/06/14 12:01] y2sunlight |
js:iteration_protocols [2021/07/12 13:38] (現在) tanaka [ジェネレーター] |
||
---|---|---|---|
行 5: | 行 5: | ||
どんな言語でもコレクション内の各アイテムに対する反復処理は必須の機能です。JavaScriptでも言語コアに反復処理の機能が直接的に取り入れられています。この機能によって、[[https:// | どんな言語でもコレクション内の各アイテムに対する反復処理は必須の機能です。JavaScriptでも言語コアに反復処理の機能が直接的に取り入れられています。この機能によって、[[https:// | ||
+ | ES2015では反復処理の為に新しい仕組みとして、[[https:// | ||
+ | * 反復可能(iterable)プロトコル | ||
+ | * 反復子(iterator)プロトコル | ||
+ | |||
+ | これらのプロトコルを使って、イテレーターオブジェクト及びジェネレーターオブジェクトが定義されています。 | ||
+ | |||
+ | \\ | ||
===== イテレーター ===== | ===== イテレーター ===== | ||
+ | イテレーターとは、コレクション内のオブジェクトを列挙する機能を持ったオブジェクトの事です。ES2015< | ||
+ | |||
+ | 以下にイテレーターを使わないレトロな for 文と、イテレーターを使用した for 文を比べてみます。 | ||
+ | |||
+ | <sxh javascript; | ||
+ | let students = [' | ||
+ | |||
+ | for(let i = 0; i < students.length; | ||
+ | console.log(students[i]); | ||
+ | } | ||
+ | </ | ||
+ | |||
+ | <sxh javascript; | ||
+ | let students = [' | ||
+ | |||
+ | for(let student of students) { | ||
+ | console.log(student); | ||
+ | } | ||
+ | </ | ||
+ | |||
+ | また、イテレーターオブジェクトを明示的に使用したコードは次の様になります。 | ||
+ | |||
+ | <sxh javascript; | ||
+ | let students = [' | ||
+ | |||
+ | // イテレーターオブジェクトの取得 | ||
+ | let it = students[Symbol.iterator](); | ||
+ | |||
+ | let obj = it.next(); | ||
+ | while(!obj.done()) { | ||
+ | console.log(obj); | ||
+ | obj = it.next(); | ||
+ | } | ||
+ | </ | ||
+ | |||
+ | Symbol.iteratorはコレクションからイテレーターを取得する為の特別なキーです。詳しくは[[https:// | ||
+ | |||
+ | \\ | ||
===== ジェネレーター ===== | ===== ジェネレーター ===== | ||
+ | |||
+ | ジェネレーターは数列などの列挙可能な値(オブジェクト)を、次々と生成し、'' | ||
+ | |||
+ | 以下にジェネレーターの簡単な例を示します。 | ||
+ | |||
+ | <sxh javascript; | ||
+ | class Student { | ||
+ | // コンストラクタの定義 | ||
+ | constructor(name) { | ||
+ | this.name = name; | ||
+ | } | ||
+ | |||
+ | // メソッドの定義 | ||
+ | greeting() { | ||
+ | console.log(`I am ${this.name}.`); | ||
+ | } | ||
+ | } | ||
+ | |||
+ | function* getStudents() { | ||
+ | yield new Student(' | ||
+ | yield new Student(' | ||
+ | yield new Student(' | ||
+ | } | ||
+ | |||
+ | for (let student of getStudents()) { | ||
+ | student.greeting(); | ||
+ | } | ||
+ | </ | ||
+ | |||
+ | 最初にジェネレーター関数が呼び出されると、コードは実行されずイテレーターオブジェクトが返されます。このオブジェクトのことをジェネレーターと呼びます。その後、呼び出し側でジェネレーターの '' | ||
+ | |||
+ | 別の例として、2000年から2100年までの閏年を計算するコードを、以下に示します。 | ||
+ | |||
+ | <sxh javascript; | ||
+ | function* genLeapYear(start_year) { | ||
+ | let year = start_year; | ||
+ | while(true) { | ||
+ | if(isLeapYear(year)) { | ||
+ | yield year; | ||
+ | } | ||
+ | year++; | ||
+ | } | ||
+ | } | ||
+ | |||
+ | function isLeapYear(year) { | ||
+ | return (year % 400 == 0) || | ||
+ | (year % 100 != 0 && year % 4 == 0); | ||
+ | } | ||
+ | |||
+ | for (let year of genLeapYear(2000)) { | ||
+ | if(year > 2100) break; | ||
+ | console.log(year); | ||
+ | } | ||
+ | </ | ||
+ | |||
+ | 上の例はジェネレーターがなぜ使われるのかを端的に示しています。この例から分かるように、ジェネレーターを使用することにより全ての計算結果が格納された配列を用意する必要がなくなります。また、計算の終了を関数の呼び出し側で行うこともできます。 | ||
+ | |||
+ | \\ | ||