The Wayback Machine - https://web.archive.org/web/20180214180538/https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Iteration_protocols

ECMAScript 2015 に追加された2つのプロトコルです(新しい構文やビルトインではありません)。規約を満たす任意のオブジェクトに実装することができます。

iterableプロトコルと iteratorプロトコルの2つのプロトコルがあります。

iterableプロトコル

iterable (反復可能)プロトコルによって、JavaScriptオブジェクトは、for..of構造で値がループしているもの等の反復動作を定義、または、カスタマイズできます。ArrayMapのように、いくつかのビルトインの型はデフォルトの反復動作を持っているビルトイン iterables です。一方、(Objectのような)他の型は反復動作を持ちません。 

iterableであるために、オブジェクトは@@iteratorメソッドを実装する必要があります。これはつまり、オブジェクト(または、prototype chainオブジェクトの一つ)が Symbol.iterator 定数にて利用できる @@iterator キーのプロパティを持つ必要があります。:

プロパティ
[Symbol.iterator] オブジェクトを返す引数なしの関数。iterator プロトコルに準拠します。

(for..ofループの始まりのように)オブジェクトが反復される必要があるときはいつでも、その@@iteratorメソッドが引数なしで呼ばれます。そして、返されるiteratorは、反復される値を取得するために使用されます。

iterator プロトコル

iterator プロトコルは、値のシーケンスを生成するための標準的な方法を定義します(有限または無限のいずれか)。

次のセマンティクスでnext()メソッドを実装するとき、オブジェクトはイテレーターです。:

プロパティ
next

引き数なしの関数。二つのプロパティを持つオブジェクトを返します。:

  • done (boolean)
    • イテレーターは、反復シーケンスの終わりを超えている場合、true値になります。この場合に、valueは、任意の方法でイテレーターのreturn valueを指定します。戻り値についてはこちらで説明されています。
    • イテレーターがシーケンス内の次の値を生成できるとき false値になります。これは、完全にdoneプロパティを指定しないのと同じです。
  • value - イテレーターによって返される任意のJavaScript値。donetrueのとき省略されます。

next メソッドは常に donevalue の適切なプロパティと共にオブジェクトを返します。非オブジェクト値が返される場合(例えば falseundefined)、TypeError ("iterator.next() returned a non-object value") が投げられます。

いくつかのイテレーターは次々にイテレート可能です:

var someArray = [1, 5, 7];
var someArrayEntries = someArray.entries();

someArrayEntries.toString();           // "[object Array Iterator]"
someArrayEntries === someArrayEntries[Symbol.iterator]();    // true

例: iteration protocolsを使う

Stringはビルトイン反復可能オブジェクトの例です。:

var someString = "hi";
typeof someString[Symbol.iterator];          // "function"

Stringデフォルトイテレーターは一つづつStringの文字を返します。:

var iterator = someString[Symbol.iterator]();
iterator + "";                               // "[object String Iterator]"
 
iterator.next();                             // { value: "h", done: false }
iterator.next();                             // { value: "i", done: false }
iterator.next();                             // { value: undefined, done: true }

spread演算子のように、内部で同じ反復プロトコルを使っているビルトインコンストラクタもあります:

[...someString]                              // ["h", "i"]

自身の@@iteratorを供給することによって反復動作を再定義できます。:

var someString = new String("hi");          // need to construct a String object explicitly to avoid auto-boxing

someString[Symbol.iterator] = function() {
  return { // this is the iterator object, returning a single element, the string "bye"
    next: function() {
      if (this._first) {
        this._first = false;
        return { value: "bye", done: false };
      } else {
        return { done: true };
      }
    },
    _first: true
  };
};

@@iteratorを再定義することによって、iterationプロトコルを使用するビルトインコンストラクタの動作にどれほど影響を与えるか注意してください:

[...someString];                              // ["bye"]
someString + "";                              // "hi"

反復の例

ビルトインの反復可能オブジェクト

StringArrayTypedArrayMapSetは、すべてのビルトイン反復可能オブジェクトです。というのも、それらすべてのプロトタイプオブジェクトは@@iteratorメソッドをもつからです。

ユーザ定義反復可能オブジェクト

下記のように反復可能オブジェクトを生成できます。:

var myIterable = {};
myIterable[Symbol.iterator] = function* () {
    yield 1;
    yield 2;
    yield 3;
};
[...myIterable]; // [1, 2, 3]

反復可能オブジェクトを受け入れる組み込みAPI

反復可能オブジェクトを受け入れる多くのAPIがあります。例えば: Map([iterable])WeakMap([iterable])Set([iterable])WeakSet([iterable]):

var myObj = {};
new Map([[1,"a"],[2,"b"],[3,"c"]]).get(2);               // "b"
new WeakMap([[{},"a"],[myObj,"b"],[{},"c"]]).get(myObj); // "b"
new Set([1, 2, 3]).has(3);                               // true
new Set("123").has("2");                                 // true
new WeakSet(function*() {
    yield {};
    yield myObj;
    yield {};
}()).has(myObj);                                         // true

他には、Promise.all(iterable)Promise.race(iterable)Array.from()があります。

反復可能オブジェクトを期待する構文

いくつかのステートメントや式は反復可能オブジェクトを期待しています。例えば、for-of ループ、spread syntaxyield*destructuring assignment

for(let value of ["a", "b", "c"]){
    console.log(value);
}
// "a"
// "b"
// "c"

[..."abc"]; // ["a", "b", "c"]

function* gen(){
  yield* ["a", "b", "c"];
}

gen().next(); // { value:"a", done:false }

[a, b, c] = new Set(["a", "b", "c"]);
a // "a"

非整形反復可能オブジェクト

反復可能オブジェクトの@@iterator メソッドが反復オブジェクトを返さない場合、その反復可能オブジェクトは非整形反復可能オブジェクトです。それは、ランタイム例外やバグの挙動をもたらす可能性があります。:

var nonWellFormedIterable = {}
nonWellFormedIterable[Symbol.iterator] = () => 1
[...nonWellFormedIterable] // TypeError: [] is not a function

イテレーターの例

簡単なイテレーター

function makeIterator(array){
    var nextIndex = 0;
    
    return {
       next: function(){
           return nextIndex < array.length ?
               {value: array[nextIndex++], done: false} :
               {done: true};
       }
    };
}

var it = makeIterator(['yo', 'ya']);

console.log(it.next().value); // 'yo'
console.log(it.next().value); // 'ya'
console.log(it.next().done);  // true

無限のイテレーター

function idMaker(){
    var index = 0;
    
    return {
       next: function(){
           return {value: index++, done: false};
       }
    };
}

var it = idMaker();

console.log(it.next().value); // '0'
console.log(it.next().value); // '1'
console.log(it.next().value); // '2'
// ...

ジェネレータとともに

function* makeSimpleGenerator(array){
    var nextIndex = 0;
    
    while(nextIndex < array.length){
        yield array[nextIndex++];
    }
}

var gen = makeSimpleGenerator(['yo', 'ya']);

console.log(gen.next().value); // 'yo'
console.log(gen.next().value); // 'ya'
console.log(gen.next().done);  // true



function* idMaker(){
    var index = 0;
    while(true)
        yield index++;
}

var gen = idMaker();

console.log(gen.next().value); // '0'
console.log(gen.next().value); // '1'
console.log(gen.next().value); // '2'
// ...

ECMAScript 6 class とともに

class SimpleClass {
  constructor(data) {
    this.index = 0;
    this.data = data;
  }

  [Symbol.iterator]() {
    return {
      next: () => {
        if (this.index < this.data.length) {
          return {value: this.data[this.index++], done: false};
        } else {
          this.index = 0; //If we would like to iterate over this again without forcing manual update of the index
          return {done: true};
        }
      }
    }
  };
}

const simple = new SimpleClass([1,2,3,4,5]);

for (const val of simple) {
  console.log(val);  //'0' '1' '2' '3' '4' '5' 
}

ジェネレータは、イテレーターまたは反復可能なオブジェクトですか?

generatorオブジェクトは、イテレーターであり、反復可能オブジェクトです。:

var aGeneratorObject = function*(){
    yield 1;
    yield 2;
    yield 3;
}();
typeof aGeneratorObject.next;
// "function", because it has a next method, so it's an iterator
typeof aGeneratorObject[Symbol.iterator];
// "function", because it has an @@iterator method, so it's an iterable
aGeneratorObject[Symbol.iterator]() === aGeneratorObject;
// true, because its @@iterator method return its self (an iterator), so it's an well-formed iterable
[...aGeneratorObject];
// [1, 2, 3]

ブラウザ実装状況

We're converting our compatibility data into a machine-readable JSON format. This compatibility table still uses the old format, because we haven't yet converted the data it contains. Find out how you can help!

機能 Chrome Firefox (Gecko) Internet Explorer Opera Safari (WebKit)
基本サポート 39.0 27.0 (27.0) 未サポート 26 10
IteratorResult object instead of throwing (有) 29.0 (29.0) 未サポート (有) 10
機能 Android Android Webview Firefox Mobile (Gecko) IE Mobile Opera Mobile Safari Mobile Chrome for Android
基本サポート 未サポート (有) 27.0 (27.0) 未サポート 未サポート 10 39.0
IteratorResult object instead of throwing 未サポート ? 29.0 (29.0) 未サポート 未サポート ? (有)

Firefox-固有の注意

IteratorResult オブジェクトが例外の代わりに返される

Gecko 29 (Firefox 29 / Thunderbird 29 / SeaMonkey 2.26) 以降、ジェネレーター関数は TypeError "generator has already finished" を投げません、その代わりに{ value: undefined, done: true } のような IteratorResult オブジェクトを返します (バグ 958951).

Iterator プロパティと @@iterator シンボル

Gecko 17 (Firefox 17 / Thunderbird 17 / SeaMonkey 2.14) から Gecko 26 (Firefox 26 / Thunderbird 26 / SeaMonkey 2.23 / Firefox OS 1.2) まで、 iterator プロパティが使われていました (bug 907077)、そして Gecko 27 から Gecko 35 では "@@iterator" プレースホルダが使われていました。Gecko 36 (Firefox 36 / Thunderbird 36 / SeaMonkey 2.33) にて @@iterator symbol が実装されました(bug 918828)。

仕様

仕様 ステータス コメント
ECMAScript 2015 (6th Edition, ECMA-262)
Iteration の定義
標準 初期定義。
ECMAScript Latest Draft (ECMA-262)
Iteration の定義
ドラフト  

関連情報

ES2015ジェネレータの詳細について、function*() 文書をご覧ください。

ドキュメントのタグと貢献者

 このページの貢献者: Uemmra3, kdex, ambi, mushahiroyuki, shide55
 最終更新者: Uemmra3,
HTTPS · web.archive.org
← Home