- JavaScript
JavaScriptループ7種|forEachのbreak・for of/in比較
JavaScriptのループは、for・while・do...while・for...of・for...in・forEach・map などの配列メソッドの7系統です。 配列を先頭から回すなら for...of、途中で止める必要がなければ forEach、オブジェクトのキーを回すなら Object.entries() + for...of を選ぶと、ほとんどの場面に対応できます。
この記事では、Node.js 22.22.2 で実際に動かした出力をもとに、「forEach で break するとどうなるか(実際のエラー文)」「for...in で配列を回したときに何が起きるか」「forEach の中の await が待たない理由」を再現し、それぞれの直し方を 直す前と後 で示します。ループの選び方を1枚で判断できる比較表と、100万件での速度の参考計測も載せています。
JavaScriptループの早見表
まずはこの表で「どのループが何をできるか」がわかります。
| 書き方 | 主な対象 | break / continue | await で1件ずつ待つ | index の取り方 | 戻り値 |
|---|---|---|---|---|---|
for (let i = 0; ...; i++) |
回数・配列 | ○ / ○ | ○ | i |
なし |
while (条件) |
条件が真の間 | ○ / ○ | ○ | 自分で数える | なし |
do { } while (条件) |
最低1回は実行 | ○ / ○ | ○ | 自分で数える | なし |
for (const v of 反復可能) |
配列・文字列・Map・Set・NodeList | ○ / ○ | ○ | arr.entries() で [i, v] |
なし |
for (const k in オブジェクト) |
オブジェクトのキー | ○ / ○ | ○ | キー(文字列) | なし |
arr.forEach(fn) |
配列・Map・Set・NodeList | ×(return で次へ) |
×(待たない) | 第2引数 (v, i) |
undefined |
arr.map / filter / some / every / find など |
配列 | some・every・find は途中で終了できる | × | 第2引数 (v, i) |
新しい配列・真偽値・要素 |
迷ったときの選び方
| やりたいこと | おすすめ |
|---|---|
| 配列を順に処理し、途中で止めたい | for...of |
| 配列の index も欲しい | for (const [i, v] of arr.entries()) または for |
| 全件に同じ処理(止めない) | forEach |
| 新しい配列を作る | map / filter(別記事「map filter reduce」で詳しく解説) |
| 条件に合う最初の1件だけ | find / findIndex |
| 1件でも条件に合うか | some |
| オブジェクトのキーと値 | Object.entries() + for...of |
| 非同期処理を順番に | for...of + await |
| 非同期処理を同時に | Promise.all + map |
| 回数が決まっていない | while |
本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。
(記載例)出典:株式会社RJC「JavaScriptループ7種|forEachのbreak・for of/in比較」
7種類のループの基本の書き方
それぞれの基本形を1つのファイルで動かします。 以降のコードはすべて Node.js 22.22.2 で node ファイル名 として実行しています。
// basic.js
const items = ['ノートPC', 'モニター', 'チェア'];
console.log('--- for');
for (let i = 0; i < items.length; i++) console.log(i, items[i]);
console.log('--- while');
let n = 0;
while (n < 2) { console.log('while', n); n++; }
console.log('--- do...while');
let m = 10;
do { console.log('do-while は条件が偽でも1回実行', m); } while (m < 5);
console.log('--- for...of');
for (const item of items) console.log(item);
console.log('--- for...of + entries()');
for (const [i, item] of items.entries()) console.log(i, item);
console.log('--- for...in (オブジェクト)');
const stock = { pc: 3, monitor: 5 };
for (const key in stock) console.log(key, stock[key]);
console.log('--- forEach');
items.forEach((item, i) => console.log(i, item));
console.log('--- map');
console.log(items.map((item, i) => `${i + 1}. ${item}`));
実行結果(Node.js 22.22.2):
--- for
0 ノートPC
1 モニター
2 チェア
--- while
while 0
while 1
--- do...while
do-while は条件が偽でも1回実行 10
--- for...of
ノートPC
モニター
チェア
--- for...of + entries()
0 ノートPC
1 モニター
2 チェア
--- for...in (オブジェクト)
pc 3
monitor 5
--- forEach
0 ノートPC
1 モニター
2 チェア
--- map
[ '1. ノートPC', '2. モニター', '3. チェア' ]
ポイント
- do...while は条件を後で判定するので、条件が最初から偽でも1回は実行されます。 「1回は入力を受け付けて、正しくなるまで繰り返す」ような処理に向いています。
- for...of で index も欲しいときは
entries()を使うと、[index, 値]の組で取り出せます。 - for...of は「値」、for...in は「キー」 を取り出します。名前が似ていますが役割がまったく違います。
forEachでbreakしたいときの書き方
forEach の中では break も continue も使えません。 書くと、実行前の構文チェックの段階でエラーになります。
直す前:forEach の中に break を書く
// break_err.js
const items = ['ノートPC', 'モニター', 'チェア'];
items.forEach((item) => {
if (item === 'モニター') break;
console.log(item);
});
実行結果:
/…/break_err.js:3
if (item === 'モニター') break;
^^^^^
SyntaxError: Illegal break statement
continue の場合も同様です。
SyntaxError: Illegal continue statement: no surrounding iteration statement
なぜエラーになるのか:forEach に渡しているのは「ループ」ではなく「関数」だからです。 break と continue は for や while などのループ構文の中でしか使えません。forEach は配列の要素ごとに関数を呼び出すメソッドなので、関数の中から外側のループを止める手段がありません。
return は continue の代わりになる
forEach の中で return すると、その要素の関数だけが終わり、次の要素に進みます。 つまり return は continue と同じ働きになり、break にはなりません。
直した後:目的別の代替手段
// foreach_return.js
const tasks = [
{ id: 1, title: '備品の発注', done: true },
{ id: 2, title: '在庫の確認', done: false },
{ id: 3, title: '棚卸し', done: false },
{ id: 4, title: '会員リスト更新', done: false },
];
console.log('--- forEach + return(continue 相当)');
tasks.forEach((t) => {
if (t.done) return; // この要素だけ飛ばす
console.log(t.id, t.title);
});
console.log('--- forEach の戻り値');
console.log(tasks.forEach(() => 'x'));
console.log('--- for...of + break / continue');
for (const t of tasks) {
if (t.done) continue;
if (t.id === 3) break;
console.log(t.id, t.title);
}
console.log('--- some(true を返した時点で終了)');
let visited = [];
const hasPending = tasks.some((t) => { visited.push(t.id); return !t.done; });
console.log(hasPending, '見た要素:', visited);
console.log('--- every(false を返した時点で終了)');
visited = [];
tasks.every((t) => { visited.push(t.id); return t.id < 2; });
console.log('見た要素:', visited);
console.log('--- find / findIndex');
console.log(tasks.find((t) => !t.done));
console.log(tasks.findIndex((t) => !t.done));
console.log('--- ラベル付き break(二重ループ)');
const grid = [[1, 2], [3, 4], [5, 6]];
outer: for (const row of grid) {
for (const v of row) {
if (v === 4) break outer;
console.log(v);
}
}
console.log('--- try/throw で forEach を抜ける(参考)');
try {
tasks.forEach((t) => { if (t.id === 2) throw new Error('stop'); console.log(t.id); });
} catch (e) { console.log('抜けた:', e.message); }
実行結果:
--- forEach + return(continue 相当)
2 在庫の確認
3 棚卸し
4 会員リスト更新
--- forEach の戻り値
undefined
--- for...of + break / continue
2 在庫の確認
--- some(true を返した時点で終了)
true 見た要素: [ 1, 2 ]
--- every(false を返した時点で終了)
見た要素: [ 1, 2 ]
--- find / findIndex
{ id: 2, title: '在庫の確認', done: false }
1
--- ラベル付き break(二重ループ)
1
2
3
--- try/throw で forEach を抜ける(参考)
1
抜けた: stop
some は true を返した時点、every は false を返した時点で残りの要素を見ずに終わります。 「見た要素」が [1, 2] で止まっていることから、id 3・4 は処理されていないことがわかります。
forEach の break 代替の比較表
| 方法 | 途中で止まる | 戻り値 | 読みやすさ | 向いている場面 |
|---|---|---|---|---|
| for...of + break | ○ | なし | ◎ 意図がそのまま読める | 迷ったらこれ |
some |
○(true で終了) | 真偽値 | ○ | 「1件でもあるか」を調べる |
every |
○(false で終了) | 真偽値 | ○ | 「全件が条件を満たすか」を調べる |
find / findIndex |
○(見つけたら終了) | 要素 / 番号 | ◎ | 最初の1件を取り出す |
| forEach + return | ×(その要素だけ飛ばす) | undefined |
○ | continue 相当として使う |
| try/throw | ○ | なし | △ 例外を流れの制御に使う | 他の手段がないときの参考 |
| ラベル付き break | ○(外側まで抜ける) | なし | ○ | for...of の二重ループ |
「止めたい」なら for...of、「探したい」なら find、「あるか知りたい」なら some と、目的の言葉で選ぶと迷いません。
for...ofとfor...inの違い
for...of は値を、for...in はキー(プロパティ名)を順に取り出します。 配列に for...in を使うと、意図しない動きになることがあります。
| 項目 | for...of | for...in |
|---|---|---|
| 取り出すもの | 値 | キー(文字列) |
| 対象 | 反復可能なもの(配列・文字列・Map・Set・NodeList など) | オブジェクトのプロパティ |
| 配列の index の型 | (entries() を使えば数値) |
文字列 "0" "1" |
| プロトタイプ(継承元)に追加したプロパティ | 出ない | 出る |
| 配列に後から付けたプロパティ | 出ない | 出る |
| 普通のオブジェクト | そのままでは使えない(TypeError) | 使える |
| 速度(配列100万件の参考値) | 約1ms | 約130ms |
直す前:for...in で配列を回す
// forin.js
const items = ['ノートPC', 'モニター', 'チェア'];
console.log('--- for...in で配列');
for (const i in items) console.log(i, typeof i, i + 1);
console.log('--- プロトタイプに追加したプロパティ');
Array.prototype.myHelper = function () {};
for (const i in items) console.log('for...in:', i);
for (const item of items) console.log('for...of:', item);
delete Array.prototype.myHelper;
console.log('--- 配列に独自プロパティ');
const list = ['a', 'b'];
list.note = 'メモ';
console.log('for...in:', Object.keys(list));
console.log('for...of:', [...list]);
console.log('--- 疎な配列(穴あき)');
const sparse = [1, , 3];
sparse.forEach((v, i) => console.log('forEach', i, v));
for (const v of sparse) console.log('for...of', v);
for (const i in sparse) console.log('for...in', i);
console.log('--- オブジェクトの継承プロパティ');
const base = { shared: true };
const obj = Object.create(base);
obj.own = 1;
for (const k in obj) console.log('for...in:', k);
console.log('Object.keys:', Object.keys(obj));
for (const k in obj) if (Object.hasOwn(obj, k)) console.log('hasOwn で絞る:', k);
実行結果:
--- for...in で配列
0 string 01
1 string 11
2 string 21
--- プロトタイプに追加したプロパティ
for...in: 0
for...in: 1
for...in: 2
for...in: myHelper
for...of: ノートPC
for...of: モニター
for...of: チェア
--- 配列に独自プロパティ
for...in: [ '0', '1', 'note' ]
for...of: [ 'a', 'b' ]
--- 疎な配列(穴あき)
forEach 0 1
forEach 2 3
for...of 1
for...of undefined
for...of 3
for...in 0
for...in 2
--- オブジェクトの継承プロパティ
for...in: own
for...in: shared
Object.keys: [ 'own' ]
hasOwn で絞る: own
読み取れることは4つです。
- for...in の index は文字列なので、
i + 1が"01"のような文字列連結になります。 - プロトタイプに追加された
myHelperまで列挙されます。 ライブラリが組み込みオブジェクトを拡張していると、配列の要素以外が混ざります。 - 配列に付けた独自プロパティ(
note)も列挙されます。 - 穴あき配列では、forEach と for...in は穴を飛ばし、for...of は
undefinedとして回ります。
直した後:配列は for...of、オブジェクトは Object.entries
| 回したいもの | 書き方 |
|---|---|
| 配列の値 | for (const v of arr) |
| 配列の index と値 | for (const [i, v] of arr.entries()) |
| オブジェクトのキー | for (const k of Object.keys(obj)) |
| オブジェクトの値 | for (const v of Object.values(obj)) |
| オブジェクトのキーと値 | for (const [k, v] of Object.entries(obj)) |
| for...in を使うなら | if (Object.hasOwn(obj, k)) で自分のプロパティに絞る |
Object.keys / values / entries は、自分自身が持つプロパティだけを返します。 for...in と違い、継承元のプロパティは含まれません。
forEachの中でawaitが待たない理由と書き方
forEach の中に async 関数を渡しても、forEach は1件ごとの完了を待ちません。 非同期の処理を回すときは、順番に処理するなら for...of + await、同時に処理するなら Promise.all を使います。
// await.mjs(トップレベル await を使うため .mjs)
const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
const fetchStock = async (id) => { await sleep(100); return { id, stock: id * 10 }; };
const ids = [1, 2, 3];
const ms = (t) => `${Math.round((performance.now() - t) / 100) * 100}ms`;
let t = performance.now();
const r1 = [];
ids.forEach(async (id) => { r1.push(await fetchStock(id)); });
console.log('forEach + await 直後:', r1, ms(t));
t = performance.now();
const r2 = [];
for (const id of ids) r2.push(await fetchStock(id));
console.log('for...of + await(順番に):', r2.map((x) => x.stock), ms(t));
t = performance.now();
const r3 = await Promise.all(ids.map((id) => fetchStock(id)));
console.log('Promise.all(同時に):', r3.map((x) => x.stock), ms(t));
t = performance.now();
const r4 = ids.map(async (id) => fetchStock(id));
console.log('map + async だけ:', r4);
const failing = async (id) => { await sleep(50); if (id === 2) throw new Error(`id=${id} 失敗`); return id; };
try { await Promise.all(ids.map(failing)); } catch (e) { console.log('Promise.all は1つ失敗で reject:', e.message); }
const settled = await Promise.allSettled(ids.map(failing));
console.log('allSettled:', settled.map((s) => s.status));
console.log('for await...of:');
async function* gen() { for (const id of ids) { await sleep(10); yield id; } }
for await (const id of gen()) console.log(' ', id);
実行結果(時間は100ms単位に丸めています):
forEach + await 直後: [] 0ms
for...of + await(順番に): [ 10, 20, 30 ] 300ms
Promise.all(同時に): [ 10, 20, 30 ] 100ms
map + async だけ: [ Promise { <pending> }, Promise { <pending> }, Promise { <pending> } ]
Promise.all は1つ失敗で reject: id=2 失敗
allSettled: [ 'fulfilled', 'rejected', 'fulfilled' ]
for await...of:
1
2
3
forEach の直後では結果がまだ空([])です。 forEach は渡した async 関数が返す Promise を受け取らずに次へ進むため、全件の完了を待つ手段がありません。一方、for...of + await は1件ずつ待つので合計約300ms、Promise.all は3件を同時に走らせるので約100ms で終わりました。
非同期ループの使い分け
| 書き方 | 実行のしかた | 所要時間(100ms×3件) | 1件失敗したとき | 向いている場面 |
|---|---|---|---|---|
| forEach + async | 待たない | (完了を待てない) | 捕まえにくい | 非同期では使わない |
| for...of + await | 1件ずつ順番に | 約300ms | その場で止まる(try/catch で捕まえられる) | 順番が大事、相手の負荷を抑えたい |
| Promise.all + map | 同時に | 約100ms | 全体が reject | 互いに独立した処理をまとめて速く |
| Promise.allSettled + map | 同時に | 約100ms | 成功・失敗を両方受け取る | 一部失敗しても続けたい |
| for await...of | 非同期に届く値を順に | — | try/catch | ストリーム・非同期ジェネレーター |
map に async 関数を渡すだけでは、Promise の配列ができるだけです。 必ず await Promise.all(...) で受け取りましょう。大量の件数を同時に送るとサーバーに負荷がかかるため、件数が多いときは数件ずつに分けて Promise.all する方法もあります。
オブジェクト・Map・Set・NodeListの回し方
ループの対象によって、使える書き方が変わります。
// collections.js
const stock = { pc: 3, monitor: 5, chair: 0 };
console.log('--- Object.keys / values / entries');
console.log(Object.keys(stock));
console.log(Object.values(stock));
for (const [key, value] of Object.entries(stock)) console.log(key, value);
console.log('--- オブジェクトに for...of はそのまま使えない');
try { for (const x of stock) console.log(x); } catch (e) { console.log(e.constructor.name + ':', e.message); }
console.log('--- オブジェクトに forEach もない');
try { stock.forEach(() => {}); } catch (e) { console.log(e.constructor.name + ':', e.message); }
console.log('--- Map');
const members = new Map([['m001', '佐藤'], ['m002', '鈴木']]);
for (const [id, name] of members) console.log(id, name);
members.forEach((name, id) => console.log('forEach', id, name));
console.log('--- Set');
const tags = new Set(['新着', 'セール', '新着']);
for (const tag of tags) console.log(tag);
tags.forEach((v, v2) => console.log('forEach', v, v2));
console.log('--- 文字列(絵文字も1文字ずつ)');
const text = '在庫😀';
for (const ch of text) console.log(ch);
console.log('length:', text.length, '/ for...of の回数:', [...text].length);
console.log('--- 回数だけ回す');
Array.from({ length: 3 }, (_, i) => console.log('Array.from', i));
for (const i of Array(3).keys()) console.log('keys()', i);
実行結果:
--- Object.keys / values / entries
[ 'pc', 'monitor', 'chair' ]
[ 3, 5, 0 ]
pc 3
monitor 5
chair 0
--- オブジェクトに for...of はそのまま使えない
TypeError: stock is not iterable
--- オブジェクトに forEach もない
TypeError: stock.forEach is not a function
--- Map
m001 佐藤
m002 鈴木
forEach m001 佐藤
forEach m002 鈴木
--- Set
新着
セール
forEach 新着 新着
forEach セール セール
--- 文字列(絵文字も1文字ずつ)
在
庫
😀
length: 4 / for...of の回数: 3
--- 回数だけ回す
Array.from 0
Array.from 1
Array.from 2
keys() 0
keys() 1
keys() 2
注目したい点
- 普通のオブジェクトは反復可能ではないため、for...of は
TypeError: stock is not iterableになります。 Object.entries() で配列にしてから回します。 - Map の forEach はコールバックの引数が
(値, キー)の順です。for...of では[キー, 値]の順で取り出せます。 - Set の forEach は第1・第2引数が同じ値になります(Map と形をそろえるための仕様です)。
- 文字列の for...of は絵文字を1文字として扱います。
lengthは4ですが、for...of は3回です。
NodeList と HTMLCollection(ブラウザ)
ブラウザの DOM で取得した要素の一覧も、種類によって使える書き方が違います。Playwright で Chromium 141 を起動し、ページ内で次のコードを実行しました。
const list = document.querySelectorAll('.item');
list.forEach((li, i) => console.log(i, li.textContent)); // 使える
for (const li of list) console.log(li.textContent); // 使える
console.log(typeof list.map); // undefined
console.log(Array.from(list, (li) => li.textContent)); // 配列にすれば map と同じことができる
const hc = document.getElementsByClassName('item');
console.log(typeof hc.forEach); // undefined
for (const li of hc) console.log(li.textContent); // for...of は使える
実行結果(Chromium 141.0.7390.37、<li class="item"> を2つ置いたページ):
querySelectorAll: NodeList
forEach 0 ノートPC
forEach 1 モニター
for...of ノートPC
for...of モニター
NodeList に map: undefined
Array.from + map: ["ノートPC","モニター"]
getElementsByClassName: HTMLCollection / forEach: undefined
HTMLCollection for...of ノートPC
HTMLCollection for...of モニター
| 対象 | for...of | forEach | map などの配列メソッド | 備考 |
|---|---|---|---|---|
| 配列 | ○ | ○ | ○ | |
| 普通のオブジェクト | × | × | × | Object.entries() で配列にする |
| Map | ○([キー, 値]) |
○((値, キー)) |
× | [...map] で配列に |
| Set | ○ | ○ | × | [...set] で配列に |
| 文字列 | ○(文字単位) | × | × | [...str] で配列に |
| NodeList(querySelectorAll) | ○ | ○ | × | Array.from(list) で配列に |
| HTMLCollection(getElementsBy〜) | ○ | × | × | Array.from(hc) で配列に |
どの対象でも for...of は使えるため、「とりあえず for...of」と覚えておくと書き分けに迷いません。
ループの速度の参考計測
100万件の数値配列を合計する処理で、ループごとの所要時間を計測しました。 各方法を5回ずつ予行で動かしたあと、7回計測した中央値です。
// bench.js
const N = 1_000_000;
const arr = Array.from({ length: N }, (_, i) => i);
const cases = {
'for': () => { let s = 0; for (let i = 0; i < arr.length; i++) s += arr[i]; return s; },
'while': () => { let s = 0, i = 0; while (i < arr.length) s += arr[i++]; return s; },
'for...of': () => { let s = 0; for (const v of arr) s += v; return s; },
'forEach': () => { let s = 0; arr.forEach((v) => { s += v; }); return s; },
'reduce': () => arr.reduce((s, v) => s + v, 0),
'for...in': () => { let s = 0; for (const i in arr) s += arr[i]; return s; },
};
for (const fn of Object.values(cases)) for (let k = 0; k < 5; k++) fn(); // ウォームアップ
for (const [name, fn] of Object.entries(cases)) {
const times = [];
for (let k = 0; k < 7; k++) { const t = performance.now(); fn(); times.push(performance.now() - t); }
times.sort((a, b) => a - b);
console.log(name.padEnd(9), '中央値', times[3].toFixed(2), 'ms');
}
実行結果(Node.js 22.22.2、2コアのLinuxコンテナ、2回実行):
| ループ | 1回目 | 2回目 |
|---|---|---|
| for | 0.83 ms | 2.31 ms |
| while | 0.84 ms | 0.80 ms |
| for...of | 1.03 ms | 0.83 ms |
| forEach | 11.50 ms | 11.56 ms |
| reduce | 11.72 ms | 11.71 ms |
| for...in | 136.20 ms | 129.03 ms |
読み方のポイント
- for・while・for...of はほぼ同じ速さでした(for の2回目のように、1ms前後の差は実行ごとにぶれます)。
- forEach・reduce は関数呼び出しが入るぶん、この計測では約10倍の時間でしたが、100万件でも約12ms です。数百〜数千件の配列では体感できる差にはなりにくいので、読みやすさで選んで問題ありません。
- for...in は配列に対しては約130ms と大きく時間がかかりました。 キーを文字列として列挙するしくみのためです。配列には for...of を使いましょう。
- 速度は Node.js のバージョンや処理内容で変わります。性能が重要な箇所は、自分のコードで計測してから判断するのが確実です。
ループでよくあるつまずきと直し方
| 症状 | 原因 | 直し方 |
|---|---|---|
SyntaxError: Illegal break statement |
forEach の中で break | for...of + break、または some / find |
| forEach の return で止まらない | return は continue 相当 | for...of + break |
index を足したら "01" になった |
for...in のキーは文字列 | for...of + entries()、または Number(i) |
| 配列の要素以外のキーが出てくる | for...in がプロトタイプや独自プロパティを列挙 | 配列は for...of、オブジェクトは Object.entries |
TypeError: obj is not iterable |
普通のオブジェクトに for...of | Object.entries(obj) を回す |
TypeError: x.forEach is not a function |
オブジェクトや HTMLCollection に forEach | Object.entries / Array.from で配列にする |
| forEach の後で結果が空 | forEach は await を待たない | for...of + await、または Promise.all |
| map の結果が Promise の配列 | async 関数を map に渡しただけ | await Promise.all(arr.map(...)) |
| while が終わらない | 条件を変える処理を書き忘れた | ループ内でカウンターや条件の値を必ず更新する |
| ループ中に配列を削除して要素が飛ぶ | 回している配列の長さが変わる | filter で新しい配列を作る、または後ろから回す |
よくある質問
Q. forEach と for...of はどちらを使うのがよいですか? A. 途中で止める・await を使う可能性があるなら for...of、全件に同じ処理をするだけなら forEach が目安です。for...of は Map・Set・NodeList・文字列にも同じ書き方で使えるため、迷ったら for...of を選ぶと書き換えが少なくて済みます。
Q. forEach で break の代わりに return を書いたのに止まりません。 A. forEach の中の return は「その要素の処理を終えて次へ進む」という意味で、continue に相当します。 ループ全体を止めたいときは for...of + break、条件に合う要素を探して止めたいときは find や some を使います。
Q. for...in は使わないほうがよいのですか?
A. オブジェクトのキーを回す用途では使えます。 ただし継承元のプロパティも列挙されるため、Object.hasOwn(obj, k) で絞るか、Object.keys / Object.entries と for...of の組み合わせを使うと意図どおりの結果になります。配列には for...of を使いましょう。
Q. 非同期処理を同時に動かしたいが、件数が多いです。
A. Promise.all で全件を一度に送ると、相手のサーバーに負荷がかかることがあります。 配列を数件ずつに分け、for...of の中で await Promise.all(小分けした配列.map(...)) とすると、同時に動かす件数を抑えられます。
まとめ
- JavaScriptのループは for・while・do...while・for...of・for...in・forEach・配列メソッドの7系統
- forEach の中の break / continue は SyntaxError。return は continue 相当で、止めたいなら for...of + break、探すなら find、あるか知りたいなら some
- for...of は値、for...in はキー(文字列)。配列に for...in を使うとプロトタイプや独自プロパティまで列挙される
- オブジェクトは Object.entries() + for...of で、キーと値をまとめて回せる
- forEach は await を待たない。順番なら for...of + await、同時なら Promise.all
- Map・Set・NodeList・文字列は for...of で共通に回せる。HTMLCollection には forEach がない
- 速度差は100万件でも十数ms程度。for...in を配列に使う場合を除き、読みやすさで選んでよい
本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。
(記載例)出典:株式会社RJC「JavaScriptループ7種|forEachのbreak・for of/in比較」
株式会社RJCでは、JavaScriptのループの使い分けを仲間と学び合っています。こうした知識を共有しながら、日々技術を磨いています。
株式会社RJC ― SI事業・SES事業・AI駆動開発。RJCは一緒に成長を楽しめる会社です。
WE ARE HIRING
RJCで一緒に開発しながら、
成長を楽しみませんか?
RJCは、Web・モバイル・AIを活用した開発プロジェクトで、テックリードやPM・PMOも活躍するシステム開発会社です。会社を知る、待遇を確かめる、話を聞いてみる。気になるところ見てみてください!
- 127日年間休日
- 12時間平均残業時間
- 毎日ガチャ遊びココロも大切にする福利厚生。アマギフなどの賞品ラインナップ!
ほかにも、チケットレストラン、書籍読み放題、2年ごとの慰労報奨(休暇 or 金一封)、11期連続の黒字決算。