JavaScriptのfor、forEach、mapの違いと使い分け

1. forループ

forループは、最も基本的で柔軟性の高い反復処理の方法です。構文は以下の通りです。

for (初期化式; 条件式; 更新式) {
  // 実行されるコードブロック
}

一般的な配列の反復処理は以下のようになります。

const numbers = [10, 20, 30, 40, 50];
for (let i = 0; i < numbers.length; i++) {
  console.log(numbers[i]);
}

この方法の欠点は、ループのたびにnumbers.lengthを参照するため、パフォーマンスが若干低下することです。特に配列の長さが動的に変化する場合、意図しない動作を引き起こす可能性があります。この問題を改善するため、配列の長さを変数にキャッシュするのが一般的です。

const numbers = [10, 20, 30, 40, 50];
for (let i = 0, len = numbers.length; i < len; i++) {
  console.log(numbers[i]);
}

この書き方により、パフォーマンスが向上します。ただし、余分な変数lenが増えるというデメリットもあります。

もし反復の順序が重要でない場合は、逆順ループを検討すると良いでしょう。これにより、一部のケースでパフォーマンスが向上します。

const numbers = [10, 20, 30, 40, 50];
for (let i = numbers.length - 1; i >= 0; i--) {
  console.log(numbers[i]);
}

または、より簡潔に書くこともできます。

const numbers = [10, 20, 30, 40, 50];
for (let i = numbers.length; i--;) {
  console.log(numbers[i]);
}

forループのパフォーマンス向上のポイント:

  • 1. 適切にbreakを使用して、不要な反復を避ける。
  • 2. ループ内で変数を宣言するのではなく、事前にまとめて宣言する。
  • 3. 配列の長さをキャッシュし、不要な変数を減らす。

2. mapメソッド

mapメソッドは、配列の各要素に対して関数を適用し、その結果から新しい配列を生成します。元の配列は変更されません。

// 値型の配列の場合、新しい配列を生成
const originalValues = [1, 2, 3, 4];
const doubledValues = originalValues.map(item => item * 2);
console.log(originalValues); // [1, 2, 3, 4]
console.log(doubledValues); // [2, 4, 6, 8]

// 参照型の配列の場合、元のオブジェクトを変更
const users = [
  { id: 1, name: 'Taro' },
  { id: 2, name: 'Hanako' }
];
const updatedUsers = users.map(user => {
  user.greeting = 'Hello, ' + user.name;
  return user; // 変更されたオブジェクトを返す
});
console.log(users); // [{id: 1, name: 'Taro', greeting: 'Hello, Taro'}, ...]
console.log(updatedUsers); // 同じオブジェクトへの参照

mapは常に新しい配列を返すため、関数型プログラミングのスタイルでコードを記述するのに適しています。また、メソッドチェーンとも相性が良く、複数の処理を連続して適用できます。

3. forEachメソッド

forEachメソッドは、配列の各要素に対して関数を実行しますが、何も返しません(常にundefinedを返します)。主に副作用(配列の変更やログ出力など)のために使用されます。

// 値型の配列を直接変更することはできない
const scores = [80, 90, 70];
scores.forEach(score => score + 10); // この操作は元の配列に影響を与えない
console.log(scores); // [80, 90, 70]

// インデックスを使用して元の配列を変更する
scores.forEach((score, index) => {
  scores[index] = score + 10;
});
console.log(scores); // [90, 100, 80]

// 参照型の配列を変更する
const products = [
  { name: 'Apple', price: 100 },
  { name: 'Banana', price: 80 }
];
products.forEach(product => {
  product.discountedPrice = product.price * 0.8;
});
console.log(products);
// [
//   { name: 'Apple', price: 100, discountedPrice: 80 },
//   { name: 'Banana', price: 80, discountedPrice: 64 }
// ]

注意点:
forEachmap内でreturn文を使用しても、ループを途中で終了させることはできません。これらのメソッドは、配列のすべての要素に対してコールバック関数を実行します。ループを中断するには、forループのbreak文を使用する必要があります。

const items = ['a', 'b', 'c', 'd'];
let found = false;
items.forEach(item => {
  if (item === 'c') {
    found = true; // フラグを立てる
    // return; // これはループを止めない
  }
  console.log(item);
});
console.log('c was found:', found);

まとめ

  • forループ:最も基本的なループ。パフォーマンスの最適化が可能で、breakcontinueによる柔軟な制御ができます。
  • map:配列を変換して新しい配列を生成するのに最適。関数型プログラミングスタイルで、メソッドチェーンが可能です。
  • forEach:配列の各要素に対して副作用のある処理を実行するのに適しています。何も返さないため、単なる反復処理に使われます。

用途に応じてこれらのメソッドを選択することで、より読みやすく、効率的なコードを書くことができます。

タグ: javascript 配列操作 forループ mapメソッド forEachメソッド

7月25日 16:40 投稿