JavaScript 配列のループ
配列のループ処理(イテレーション)は、JavaScriptにおける基本中の基本となるスキルです。配列内の各要素にアクセスして操作することで、データの処理や変換といった高度な実装が可能になります。
本章では、基本的なループ構造の理解をさらに深め、JavaScriptで配列を走査する際に最も頻繁に使われ、かつ有用な手法について解説します。
1. for ループ:クラシックかつコントロール可能
反復プロセスを精密に制御する必要がある場合、標準的な for ループ は非常に強力なツールとなります。特に、各要素の インデックス(index) を知る必要がある場合に重宝します。
1.1 基本的な for ループの構造
for ループの構造は、以下の3つのパートで構成されています。
- 初期化 (Initialization): カウンタ変数(通常は
i)を宣言し、初期化します。 - 条件 (Condition): ループを継続するかどうかを決定するブーリアン式です。条件が真(
true)である限り、ループは続きます。 - 増分/減分 (Increment/Decrement): 各イテレーションの後にカウンタ変数を更新します。
配列を走査するための for ループの実装例:
const myArray = ["apple", "banana", "cherry"];
for (let i = 0; i < myArray.length; i++) {
// i は現在の要素のインデックス
console.log("インデックス " + i + " の要素は: " + myArray[i]);
}この例の仕組み:
let i = 0;は、カウンタiを配列の最初の要素のインデックスである0に初期化します。i < myArray.length;は、iが配列の長さよりも小さいかどうかをチェックする条件です。i++は、各イテレーションの後にiを1ずつ増やします。myArray[i]で、現在のインデックスiにある要素にアクセスします。
1.2 例:for ループによる配列要素の修正
for ループを使用して、配列内の要素を直接書き換えることもできます。
const numbers = [1, 2, 3, 4, 5];
for (let i = 0; i < numbers.length; i++) {
numbers[i] = numbers[i] * 2; // 各要素を 2 倍にする
}
console.log(numbers); // 出力: [2, 4, 6, 8, 10]1.3 例:逆方向のループ
for ループを使えば、配列を後ろから前へと走査することも簡単です。
const myArray = ["apple", "banana", "cherry"];
for (let i = myArray.length - 1; i >= 0; i--) {
console.log("インデックス " + i + " の要素は: " + myArray[i]);
}ここでは、ループは配列の最後のインデックス (myArray.length - 1) から開始され、i が 0 になるまで減分されます。
2. for...of ループ:簡潔かつモダン
for...of ループ は、配列のようなイテラブルなオブジェクトの値を走査するための、より簡潔で可読性の高い手法を提供します。インデックスを管理することなく、各要素に直接アクセスできるのが特徴です。
2.1 基本的な for...of の構造
const myArray = ["apple", "banana", "cherry"];
for (const element of myArray) {
console.log(element);
}この例の仕組み:
const element of myArrayがmyArray内の各要素を自動的に取り出します。- 各イテレーションにおいて、現在の要素の値が変数
elementに代入されます。
2.2 例:条件文との組み合わせ
for...of ループ内に条件分岐を組み込むことで、要素の値に応じた特定の処理を実行できます。
const numbers = [1, 2, 3, 4, 5, 6];
for (const number of numbers) {
if (number % 2 === 0) {
console.log(number + " は偶数です");
} else {
console.log(number + " は奇数です");
}
}3. for...in ループ(配列への使用には注意が必要)
for...in ループ は、本来オブジェクトの列挙可能なプロパティ(キー)を走査するために設計されたものです。配列に対しても使用可能ですが、配列のループ処理においては通常推奨されません。
これは、for...in が配列の「値」ではなく「キー (Keys)」(すなわちインデックス)を走査するためであり、また継承されたプロパティまで含んでしまう可能性があるため、予期せぬ挙動を引き起こすことがあります。
3.1 for...in の構造(なぜ配列のループに避けるべきか)
const myArray = ["apple", "banana", "cherry"];
for (const index in myArray) {
console.log("インデックス: " + index + ", 値: " + myArray[index]);
}一見、普通のループに見えますが、以下のデメリットがあります:
- 走査されるのはプロパティ名(文字列): インデックス (
"0","1","2") は数値ではなく文字列タイプとして扱われます。これにより、数学的な計算を行う際に意図しない結果を招くことがあります。 - 継承されたプロパティを含む: もし
Array.prototypeにカスタムプロパティを追加していた場合、for...inループはそれらも走査対象に含めてしまいます。 - 順序が保証されない: プロパティを走査する順序は、定義された順序と必ずしも一致するとは限りません(モダンなブラウザでは概ね一致しますが、仕様上保証されていません)。
まとめ: 配列のループ処理には for...in を避け、for または for...of を使用するようにしましょう。
3.2 for...in が有効なケース(オブジェクト)
for...in ループは、主にオブジェクト(Object)のプロパティを走査するために使用します。
const myObject = {
name: "John",
age: 30,
city: "New York"
};
for (const key in myObject) {
console.log("キー: " + key + ", 値: " + myObject[key]);
}この場合、for...in は myObject のキーである "name"、"age"、"city" を順に走査します。
4. ループの制御:break と continue
これまでに学んだ break と continue ステートメントは、配列のループ内でも非常に有効に機能します。
4.1 break ステートメント
break ステートメントは、ループを完全に終了させます。「検索」のシナリオにおいて、目的のデータが見つかった瞬間にループを止めるのに最適です。
const numbers = [1, 2, 3, 4, 5, 6];
for (const number of numbers) {
if (number > 3) {
break; // 数字が 3 より大きくなった時点でループを抜ける
}
console.log(number);
}
// 出力:
// 1
// 2
// 34.2 continue ステートメント
continue ステートメントは、現在のイテレーションの残りの処理をスキップし、即座に次のイテレーションへ移ります。「フィルタリング」のシナリオで役立ちます。
const numbers = [1, 2, 3, 4, 5, 6];
for (const number of numbers) {
if (number % 2 === 0) {
continue; // 偶数の場合はスキップして次の数字へ
}
console.log(number);
}
// 出力:
// 1
// 3
// 5