for-of で配列を走査する
for-of で配列を走査する とは
配列の要素を直接取り出せる
for-of文を学び、配列内の最大値を求める関数を書こう。本レッスンでは、for-of で配列を走査する の基本から実際の使いどころまでを整理し、現場で迷わず使える形に落とし込みます。
for-of は「配列の中身を順番に取り出す」モダンなループ
配列を扱うとき、要素を 1 つずつ処理したい場面は山ほどあります。これまでに学んだ for 文でもできますが、JavaScript には 配列専用の便利なループ構文 があります。それが今回学ぶ for-of 文です。
for-ofはES2015(ES6) で導入されたモダンな構文で、配列だけでなく文字列・Map・Set・NodeListなど、反復可能 (iterable) なものなら何でも走査できます。インデックスを意識せずに 値そのもの が手に入るのが最大の魅力で、Pythonのfor x in list:やJavaの拡張 for 文 (for (var x : list)) と同じ発想です。
まず、配列の要素を console.log で表示する処理を従来の for 文で書くとこうなります。
JavaScript
const fruits = ['apple', 'banana', 'cherry'];
for (let i = 0; i < fruits.length; i++) {
const fruit = fruits[i];
// fruit を使う
}for-of を使うと、同じことをこう書けます。
JavaScript
const fruits = ['apple', 'banana', 'cherry'];
for (const fruit of fruits) {
// fruit を使う
}圧倒的にスッキリしました。i を管理する必要も、fruits[i] で取り出す必要もありません。配列の中身に集中できます。
for-of 文の文法
JavaScript の for-of 文の基本形は次のとおりです。
JavaScript
for (const 変数 of 反復可能オブジェクト) {
// 変数を使った処理
}大事なポイントは次の通りです。
ofキーワード を使う (inではない、これは別の構文)- 左辺の変数 は
constで宣言するのが基本 (ループの中で再代入しないなら) - 右辺 には配列や文字列など、反復可能なものを書く
- 中身は 要素そのもの が
変数に入る (インデックスではない)
例えば文字列に対しても使えます。
JavaScript
for (const char of 'hello') {
// char に 'h', 'e', 'l', 'l', 'o' が順に入る
}for-of は配列だけのものではなく、反復可能ならなんでも 走査できるのがポイントです。
「
constで宣言するの? ループのたびに値が変わるのに?」という疑問は自然です。実はfor-ofのループ変数は 毎回新しいスコープで宣言 されるので、各回ごとに別のconstとして扱われます。なので再代入していないことになり、constで問題ありません。
インデックスも欲しい場合は entries
for-of は値だけを取り出しますが、「インデックスも一緒に欲しい」場面もあります。そんなときは配列の entries() メソッドと 分割代入 を組み合わせます。
JavaScript
const fruits = ['apple', 'banana', 'cherry'];
for (const [index, fruit] of fruits.entries()) {
// index に 0, 1, 2 が、fruit に値が入る
}entries() は [インデックス, 値] のペアを順番に返してくれるイテレータで、それを分割代入で 2 つの変数に取り出しています。「インデックスが必要なら entries()」と覚えておきましょう。
実行フローを図で追ってみる
for (const num of arr) のループの流れは次のとおりです。
通常の for のような「初期化・条件・更新」という 3 要素はなく、「次の要素を取って、あれば本体実行、なければ終了」というシンプルな流れになっているのが分かります。
よくある間違い
for-of 文を使い始めるとき、初心者がハマる落とし穴が 3 つあります。
ofとinを取り違える —for (const x in arr)と書くと、これはfor-in文で配列の インデックス (文字列) が返ってきます。値が欲しいときは必ずofを使いましょう- オブジェクトに対して使えると思い込む — 普通のオブジェクト (
{ name: 'Alice', age: 30 }) はiterableではないので、for (const x of obj)はエラーになります。オブジェクトを走査するときはfor-inかObject.entries()を使います - インデックスが欲しいのに無理に
for-ofで書こうとする — 自分でlet i = 0;を外に出してi++で管理し始めると、結局for文と変わりません。素直にentries()を使うか、従来のforを使いましょう
モダンな
JavaScriptでは、配列の各要素を加工するときはfor-ofよりもArray.mapArray.filterArray.reduceといった高階関数を使うのが主流です。for-ofは「副作用 (外部の変数を書き換える) を伴う処理」「途中でbreakしたい処理」のときに重宝します。場面に応じて使い分けましょう。
もうひとつ、for-of の中では break continue も普通に使えます。for-each メソッド (arr.forEach) は break できないので、「途中で抜けたい」場面では for-of のほうが便利です。
やってみよう
それでは今回の課題に取り組みましょう。やることは次の通りです。
findMax(numbers)関数の中身を埋めるfor-of文を使って配列numbersの中の 最大値 を求めて返すfindMax([3, 1, 4, 1, 5, 9, 2, 6])が9、findMax([-3, -1, -10])が-1、findMax([7])が7になるかを確認する
ヒントとして、最大値を覚えておく変数 max を「配列の最初の要素」で初期化し、for (const num of numbers) で各要素を取り出して num > max なら更新していきます。Math.max(...numbers) のような楽な書き方もありますが、今回はループの練習なので必ず for-of を使ってください。
余裕があれば、空配列 [] を渡されたときどうするかも考えてみてください。今回のテストでは空配列は扱いませんが、本番では「想定外の入力で何が起きるか」を考える癖が役立ちます。
この先のレッスンでは、オブジェクトに使える for-in や、ループ制御の break continue、ネストしたループへと進んでいきます。for-of は実務でも頻繁に使う構文なので、しっかり身体に馴染ませましょう。
よくある質問
Q. ブラウザと Node.js で動作は変わりますか?
A. JavaScript の構文・組み込み機能(配列・文字列・Promise 等)はどちらでも同じです。違いは DOM API(ブラウザ専用)と fs などのファイル系(Node 専用)など、実行環境固有の機能です。コアロジックは両方で動くため、テストもしやすくなります。
Q. ES6 以降の新機能は使っても大丈夫ですか?
A. 現代のブラウザ・Node.js は ES2020 以降の機能をほぼサポートしています。古い IE 等を対象にする必要が無ければ、let/const、アロー関数、分割代入、async/await を積極的に使ってください。トランスパイル(Babel/Vite)が必要なケースは年々減っています。
Q. TypeScript に進む価値はありますか?
A. 型情報があるとリファクタやエディタ補完が劇的に効くため、規模が大きくなるなら TypeScript への移行を強くおすすめします。最初は any を許容しつつ徐々に型を付ければ、JS の知識をそのまま活かせます。
次のレッスン
次は for-in でオブジェクトを走査する で、配列の要素を直接取り出せる for-of 文を学び、配列内の最大値を求める関数を書こう を学びます。
事前確認 — 進む前に次の 3 つができることを確認しましょう。
- for-of の要点を自分の言葉で説明できる
- このレッスンの最小コード (または操作手順) を見ずに書ける
- 練習問題やクイズで間違えた箇所を読み直して理解した
理解度チェック (30 秒)
Q. for-of とは何か、1 文で説明してください。
A. 本文の「このレッスンで分かること」または冒頭の説明文を見直し、自分の言葉で要約できれば OK。詰まったら本レッスンの最初の H2 セクションを読み返してみましょう。
関連レッスン
要件
- 関数名は
findMax、引数は数値の配列numbers1 つ、戻り値は数値 - 繰り返し処理には必ず
for-of文を使うこと (Math.maxやforではなく) - 配列が空でないことを前提としてよい (最低 1 つは要素がある)
入出力例
test-cases.txt
findMax([3,1,4,1,5,9,2,6]) → 9
findMax([-3,-1,-10]) → -1
findMax([7]) → 7
findMax([10,20,5,30,25]) → 30