for-of
ループ for-of
ループの紹介for-of
は反復可能な値でのみ動作するconst
宣言と var
宣言の比較for-of
は ES6 の新しいループで、for-in
と forEach()
の両方を置き換え、新しい反復プロトコルをサポートします。
反復可能なオブジェクト (配列、文字列、Map、Set など; 「反復可能オブジェクトとイテレーター」の章を参照) をループ処理するために使用します。
const
iterable
=
[
'a'
,
'b'
];
for
(
const
x
of
iterable
)
{
console
.
log
(
x
);
}
// Output:
// a
// b
break
と continue
は for-of
ループ内で動作します。
for
(
const
x
of
[
'a'
,
''
,
'b'
])
{
if
(
x
.
length
===
0
)
break
;
console
.
log
(
x
);
}
// Output:
// a
配列をループ処理しながら、要素とそのインデックスの両方にアクセスします (of
の前の角かっこは、分割代入を使用していることを意味します)。
const
arr
=
[
'a'
,
'b'
];
for
(
const
[
index
,
element
]
of
arr
.
entries
())
{
console
.
log
(
`
${
index
}
.
${
element
}
`
);
}
// Output:
// 0. a
// 1. b
Map の [キー, 値] エントリをループ処理します (of
の前の角かっこは、分割代入を使用していることを意味します)。
const
map
=
new
Map
([
[
false
,
'no'
],
[
true
,
'yes'
],
]);
for
(
const
[
key
,
value
]
of
map
)
{
console
.
log
(
`
${
key
}
=>
${
value
}
`
);
}
// Output:
// false => no
// true => yes
for-of
ループの紹介 for-of
を使用すると、反復可能なデータ構造 (配列、文字列、Map、Setなど) をループ処理できます。反復可能性がどのように機能するかは、「反復可能オブジェクトとイテレーター」の章で詳しく説明しています。ただし、for-of
ループを使用する場合、詳細を知る必要はありません。
const
iterable
=
[
'a'
,
'b'
];
for
(
const
x
of
iterable
)
{
console
.
log
(
x
);
}
// Output:
// a
// b
for-of
は iterable
のアイテムを順番に処理し、ループ変数 x
に一度に1つずつ割り当ててから、本体を実行します。x
のスコープはループであり、ループ内でのみ存在します。
break
と continue
を使用できます。
for
(
const
x
of
[
'a'
,
''
,
'b'
])
{
if
(
x
.
length
===
0
)
break
;
console
.
log
(
x
);
}
// Output:
// a
for-of
は次の利点を兼ね備えています。
for
ループ: break
/continue
; ジェネレーターで使用可能forEach()
メソッド: 簡潔な構文for-of
は反復可能な値でのみ動作する of
句のオペランドは、反復可能でなければなりません。つまり、プレーンオブジェクトを反復処理する場合は、ヘルパー関数が必要になります (「プレーンオブジェクトは反復可能ではない」を参照)。値が配列のような場合、Array.from()
を使用して配列に変換できます。
// Array-like, but not iterable!
const
arrayLike
=
{
length
:
2
,
0
:
'a'
,
1
:
'b'
};
for
(
const
x
of
arrayLike
)
{
// TypeError
console
.
log
(
x
);
}
for
(
const
x
of
Array
.
from
(
arrayLike
))
{
// OK
console
.
log
(
x
);
}
const
宣言と var
宣言の比較 反復変数を const
で宣言すると、反復ごとに新しい束縛 (ストレージ領域) が作成されます。次のコードスニペットでは、アロー関数を介して、後のために elem
の現在の束縛を保存しています。その後、アロー関数は elem
の同じ束縛を共有せず、それぞれ異なる束縛を持っていることがわかります。
const
arr
=
[];
for
(
const
elem
of
[
0
,
1
,
2
])
{
arr
.
push
(()
=>
elem
);
// save `elem` for later
}
console
.
log
(
arr
.
map
(
f
=>
f
()));
// [0, 1, 2]
// `elem` only exists inside the loop:
console
.
log
(
elem
);
// ReferenceError: elem is not defined
let
宣言は const
宣言と同じように機能します (ただし、束縛は変更可能です)。
反復変数を var
で宣言した場合、状況がどのように異なるかを確認することは有益です。これで、すべてのアロー関数が elem
の同じ束縛を参照します。
const
arr
=
[];
for
(
var
elem
of
[
0
,
1
,
2
])
{
arr
.
push
(()
=>
elem
);
}
console
.
log
(
arr
.
map
(
f
=>
f
()));
// [2, 2, 2]
// `elem` exists in the surrounding function:
console
.
log
(
elem
);
// 2
反復ごとに1つの束縛を持つことは、ループを介して関数を作成する場合 (たとえば、イベントリスナーを追加する場合) に非常に役立ちます。
for
ループ (let
を使用) および for-in
ループ (const
または let
を使用) でも、反復ごとの束縛を取得します。詳細については、変数の章で説明します。
これまで、宣言された反復変数を持つ for-of
のみを見てきました。ただし、他にもいくつかの形式があります。
既存の変数で反復処理できます。
let
x
;
for
(
x
of
[
'a'
,
'b'
])
{
console
.
log
(
x
);
}
オブジェクトプロパティで反復処理することもできます。
const
obj
=
{};
for
(
obj
.
prop
of
[
'a'
,
'b'
])
{
console
.
log
(
obj
.
prop
);
}
そして、配列要素で反復処理することもできます。
const
arr
=
[];
for
(
arr
[
0
]
of
[
'a'
,
'b'
])
{
console
.
log
(
arr
[
0
]);
}
for-of
と分割代入を組み合わせると、(配列としてエンコードされた) [キー, 値] ペアの反復処理に特に便利です。これは Map の場合です。
const
map
=
new
Map
().
set
(
false
,
'no'
).
set
(
true
,
'yes'
);
for
(
const
[
k
,
v
]
of
map
)
{
console
.
log
(
`key =
${
k
}
, value =
${
v
}
`
);
}
// Output:
// key = false, value = no
// key = true, value = yes
Array.prototype.entries()
も、[キー, 値] ペアの反復可能オブジェクトを返します。
const
arr
=
[
'a'
,
'b'
,
'c'
];
for
(
const
[
k
,
v
]
of
arr
.
entries
())
{
console
.
log
(
`key =
${
k
}
, value =
${
v
}
`
);
}
// Output:
// key = 0, value = a
// key = 1, value = b
// key = 2, value = c
したがって、entries()
を使用すると、反復処理されたアイテムを位置に応じて異なる方法で扱うことができます。
/** Same as arr.join(', ') */
function
toString
(
arr
)
{
let
result
=
''
;
for
(
const
[
i
,
elem
]
of
arr
.
entries
())
{
if
(
i
>
0
)
{
result
+=
', '
;
}
result
+=
String
(
elem
);
}
return
result
;
}
この関数は次のように使用します。
> toString(['eeny', 'meeny', 'miny', 'moe'])
'eeny, meeny, miny, moe'