for...of

for...ofは、反復可能オブジェクト、たとえば組込みの String, Array, 配列状オブジェクト (例えば argumentsNodeList), TypedArray, Map, Set, およびユーザー定義の反復可能オブジェクトなどに対して、反復的な処理をするループを作成します。これはオブジェクトのそれぞれの識別可能なプロパティの値に対して、実行される文を表す独自の反復フックを呼び出します。

構文

for (variable of iterable) {
  statement
}
variable
反復処理の各回において、異なるプロパティの値が variable に割り当てられます。variableconst, let, var で宣言することができます。
iterable
反復処理が行われる反復可能なプロパティを持つオブジェクトです。

Array での反復処理

const iterable = [10, 20, 30];

for (const value of iterable) {
  console.log(value);
}
// 10
// 20
// 30

letconst の代わりに使用しても、ブロック内で変数が再割り当てされます。

const iterable = [10, 20, 30];

for (let value of iterable) {
  value += 1;
  console.log(value);
}
// 11
// 21
// 31

String での反復処理

const iterable = 'boo';

for (const value of iterable) {
  console.log(value);
}
// "b"
// "o"
// "o"

TypedArray での反復処理

const iterable = new Uint8Array([0x00, 0xff]);

for (const value of iterable) {
  console.log(value);
}
// 0
// 255

Map での反復処理

const iterable = new Map([['a', 1], ['b', 2], ['c', 3]]);

for (const entry of iterable) {
  console.log(entry);
}
// ['a', 1]
// ['b', 2]
// ['c', 3]

for (const [key, value] of iterable) {
  console.log(value);
}
// 1
// 2
// 3

Set での反復処理

const iterable = new Set([1, 1, 2, 2, 3, 3]);

for (const value of iterable) {
  console.log(value);
}
// 1
// 2
// 3

arguments オブジェクトでの反復処理

arguments オブジェクトで反復処理をすると、ある JavaScript 関数にすべての引数を渡すことができます。

(function() {
  for (const argument of arguments) {
    console.log(argument);
  }
})(1, 2, 3);

// 1
// 2
// 3

DOM コレクションでの反復処理

NodeList のような DOM コレクションでの反復処理です。次の例では、read クラスを article の直下の子である段落に加えます。

// 注: これは以下のものに対応しているプラットフォームでのみ動作します。
// implemented NodeList.prototype[Symbol.iterator]
const articleParagraphs = document.querySelectorAll('article > p');

for (const paragraph of articleParagraphs) {
  paragraph.classList.add('read');
}

反復処理の終了

for...of ループ内では、break, throw, return を発生させることで反復処理を中断させることができます。この場合、反復子は閉じられます。

function* foo(){
  yield 1;
  yield 2;
  yield 3;
};

for (const o of foo()) {
  console.log(o);
  break; // 反復処理を閉じ、ループの外の実行が継続されます
}
console.log('done');

ジェネレーターでの反復処理

ジェネレーター、すなわち反復可能オブジェクトを生成する関数で反復処理することもできます。

function* fibonacci() { // ジェネレーター関数
  let [prev, curr] = [0, 1];
  while (true) {
    [prev, curr] = [curr, prev + curr];
    yield curr;
  }
}

for (const n of fibonacci()) {
  console.log(n);
  // 1000 で繰り返しを終了する
  if (n >= 1000) {
    break;
  }
}

ジェネレーターを再利用してはいけない

ジェネレーターは、for...of ループが break キーワードなどで早く終了しても再利用してはいけません。ループを抜けると、ジェネレーターは閉じられ、そこで繰り返してもそれ以上の結果は算出されません。

const gen = (function *(){
  yield 1;
  yield 2;
  yield 3;
})();
for (const o of gen) {
  console.log(o);
  break;  // 反復処理を閉じる
}

// ジェネレーターを再利用してはいけません。以下の処理は意味がありません。
for (const o of gen) {
  console.log(o); // Never called.
}

その他の反復可能オブジェクトでの反復処理

明示的に iterable プロトコルを実装しているオブジェクトで反復処理することもできます。

const iterable = {
  [Symbol.iterator]() {
    return {
      i: 0,
      next() {
        if (this.i < 3) {
          return { value: this.i++, done: false };
        }
        return { value: undefined, done: true };
      }
    };
  }
};

for (const value of iterable) {
  console.log(value);
}
// 0
// 1
// 2

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

for...in および for...of 文は、両方とも何かに対する繰り返しです。これらの主な違いは何に対する繰り返しなのかというところです。

for...in 文は、オブジェクトのすべての列挙可能なプロパティに対して、順序不定で繰り返し処理を行います。

for...of 文は、反復可能なオブジェクトが定義した順序で値を反復処理します。

次の例では、Array に対して for...of ループと for...in ループを使用した場合の違いを示しています。

Object.prototype.objCustom = function() {};
Array.prototype.arrCustom = function() {};

const iterable = [3, 5, 7];
iterable.foo = 'hello';

for (const i in iterable) {
  console.log(i); // logs 0, 1, 2, "foo", "arrCustom", "objCustom"
}

for (const i in iterable) {
  if (iterable.hasOwnProperty(i)) {
    console.log(i); // logs 0, 1, 2, "foo"
  }
}

for (const i of iterable) {
  console.log(i); // logs 3, 5, 7
}

上記のコードをステップを追って見ていきましょう。

Object.prototype.objCustom = function() {};
Array.prototype.arrCustom = function() {};

const iterable = [3, 5, 7];
iterable.foo = 'hello';

すべてのオブジェクトは objCustom プロパティを継承し、すべての Array オブジェクトは arrCustom プロパティを継承します。Object.prototypeArray.prototype にそれぞれこれらのプロパティを追加されているためです。オブジェクト iterableobjCustomarrCustom の各プロパティを、継承とプロトタイプチェーンによって継承しています。

for (const i in iterable) {
  console.log(i); // 0, 1, 2, "foo", "arrCustom", "objCustom" と出力
}

このループは iterable オブジェクトの列挙可能なプロパティのみを、順序不定で出力します。配列の要素である 3, 5, 7hello は、列挙可能なプロパティではないため出力しません。実際、これらはプロパティではなく、値です。配列の添字arrCustomobjCustom と共に出力されます。なぜプロパティが反復処理に出てこないのかが分からない場合は、array iteration and for...in にもっと詳しい説明があります。

for (const i in iterable) {
  if (iterable.hasOwnProperty(i)) {
    console.log(i); // 0, 1, 2, "foo" と出力
  }
}

このループは最初のものと似ていますが、hasOwnProperty() を使用して見つかった列挙可能なプロパティがオブジェクト自身のものであるか、すなわち継承したものでないかどうかをチェックしています。オブジェクト自身のプロパティである場合は、ログ出力します。0, 1, 2, foo は自身のプロパティである (継承されたものではない) ため出力されます。arrCustomobjCustom継承されたものであるために出力されません。

for (const i of iterable) {
  console.log(i); // 3, 5, 7 と出力
}

このループは、iterable反復可能なオブジェクトとして定義している順序でを反復処理し、ログ出力します。オブジェクトの要素である 3, 5, 7 は表示されますが、オブジェクトのプロパティは表示されません。

仕様

ブラウザーの互換性

BCD tables only load in the browser

関連情報