Iteratorについて

前回は「Symbol」について説明しました
今回は「Iterator」についてです
Iterator」、「Iterable」の順番で説明します

Iterator

Iteratorとは・・

  • 次の要素(IteratorResult)へ1つずつアクセスする方法を備えたオブジェクト
  • nextメソッドを持っていて、nextメソッドがIteratorResultを返す
  • IteratorResultはvalueプロパティとdoneプロパティを持っているオブジェクト

文章だとよくわかりませんね汗

上記の定義をコードにするとこんな感じになります

var index = 0;
var array = [1, 2, 3];

var iterator = {}; // Iteratorはオブジェクト
iterator.next = function () { // nextメソッドを持っている
    // valueプロパティとdoneプロパティを持っているIteratorResult
    var iteratorResult =  { value: array[index++], done: index > array.length };
    return iteratorResult; // nextメソッドはIteratorResultを返す
};

コードにするとたったこれだけです
Iteratorは次の要素へのアクセスする方法を提供するだけで 実際の繰り返し処理は外部に任せます

IteratorResultの各プロパティですが

  • value: Iteratorから順番に取り出した値
  • done: Iteratorから値を取り出し終えたかどうか

Iterable

Iterableとは・・

  • 反復処理の挙動が定義されたオブジェクト
  • [Symbol.iterator]メソッドを実行するとIteratorを返すオブジェクト

これも文章だとさっぱりですねw
コードで表現してみます

var iterable = {}; // Iterableはオブジェクト
iterable[Symbol.iterator] = function() { // [Symbol.iterator]メソッドを持ってる
    return iterator; // Iteratorを返す
};

前回説明したSymbol.iteratorを使ってますね
それ以外は簡単なコードです

では実際にIteratorを使ってみます

実践

var obj = {};
obj[Symbol.iterator] = function() {
    var index = 0;
    var array = [1, 2, 3];
    var iterator = {};
    iterator.next = function () {
        var iteratorResult =  { value: array[index++], done: index > array.length };
        return iteratorResult;
    };

    return iterator;
};

var iterator = obj[Symbol.iterator]();
console.log(iterator.next()); // Object {value: 1, done: false}
console.log(iterator.next()); // Object {value: 2, done: false}
console.log(iterator.next()); // Object {value: 3, done: false}
console.log(iterator.next()); // Object {value: undefined, done: true}

/* whileを使った場合
var iterator = obj[Symbol.iterator]();
var iteratorResult;
while (true) {
    iteratorResult = iterator.next();
    if (iteratorResult.done) {
        break;
    }
    console.log(iteratorResult.value);
}
*/

上記を実際に実行してみると、順番に値を取り出すことができます
ただ、この書き方だと値の取り出し方が冗長でめんどくさいですね
そこでES2015で用意されたのがfor (var v of iterable)構文です

上記の繰り返し処理はこんな感じで書けます

for (let v of obj) {
    console.log(v);
}

スッキリしましたね
Iterableの定義さえ守っていれば、自作のオブジェクトもfor (var v of iterable)構文に渡せます

内部でwhileを使った場合の処理が行われています

  1. iteratorを取得
  2. nextメソッドを呼び出し、IteratorResultを取得
  3. doneが偽の場合繰り返し、真なら終了する

ビルトインのString、Array、TypedArray、Map、Setなども反復処理が可能なオブジェクトです

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

for (let v of 'abc') console.log(v);
/*
a
b
c
*/

まとめ

そして、ジェネレータ関数で作成されるジェネレータがIterableなオブジェクトです
詳しくは次の回