1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

ひとりJavaScriptAdvent Calendar 2024

Day 10

【JavaScript】配列の要素でループするには?forofとforEachの違い

Last updated at Posted at 2024-12-09

配列の各要素でループするには、主にforof文とforEachメソッドを使う方法があります。
では、これらの方法は何が違うのでしょうか。

結論から言うと、どちらもできることはほぼ変わりません。
しかし、ちょっと違う点もあります。

この記事では以下の話を扱いません。

  • 通常のfor
  • 実行速度やパフォーマンス

forEach

forEachは配列のメソッドの一つで、配列の各要素でループするのに使われます。
例えば、以下のように配列の各要素を出力できます。

const animals = ["dog", "cat", "rabbit"]

// 引数にアロー関数を入れて呼び出す
animals.forEach(animal => { // animalには要素("dog"とか)が入る
  console.log(`Animal: ${animal}`)
})

// Animal: dog
// Animal: cat
// Animal: rabbit

できること

インデックスが使える

インデックスを使うループの場合、forEachのほうが簡単に実装できます。
これはforEachが取る関数の第二引数がインデックスになるからです。

例えば以下のようにすると、配列の中身をインデックスとともに出力することができます。

const animals = ["dog", "cat", "rabbit"]

animals.forEach((animal, index) => { // indexにはインデックス(0始まり)が入る
  console.log(`Animal ${index}: ${animal}`)
})

// Animal 0: dog
// Animal 1: cat
// Animal 2: rabbit

forofでインデックスを使う場合は、配列のentriesメソッドを使う必要があります(後述)。

できないこと

制御文が使えない

forof文ではbreakcontinueなどの制御文が使えますが、forEachはただの関数なので使えません。

const animals = ["dog", "cat", "rabbit"]

animals.forEach(animal => {
  console.log(`Animal ${index}: ${animal}`)
  break // Syntax Error!
})

その代わり、forEachは関数を取るのでreturnが使えます。
forEachでのreturnは、forof内で使うcontinueと同じことができます。

const animals = ["dog", "cat", "rabbit"]

animals.forEach((animal, index) => {
  if (index === 1) return // indexが1なら出力しない
  console.log(`Animal ${index}: ${animal}`)
})

// Animal 0: dog
// Animal 2: rabbit

ループを中断できない

forEachのループは途中で中断できません。

forof文ではbreakを使うと中断できますが、forEachでは関数内で例外を投げる必要があります。

[1, 2, 5].forEach(x => {
  if (x % 2 === 0) throw x // 偶数がひとつでも見つかったら中断
  console.log(x)
})

// 1
// Uncaught 2

例外を投げる場合、その例外がどこまで影響を与えるのかを考える必要があります。

上のコードのようにforEachの呼び出しをtry-catchで囲んでいない場合、想定外のところまでエラーが伝播するかもしれません。

これはforof文でも`同じで、途中でエラーを投げるとループを中断できます。

しかしforofにはその役割を果たすbreakがあります。
そのためループを中断するためだけにエラーを投げることはないです。

forof

forof文は反復可能オブジェクトをループする構文です。

const array = [1, 4, 5]

// for (const 要素を入れる変数名 of 反復可能オブジェクト) { 処理 }
for (const num of array) {
  console.log(num)
}

反復可能オブジェクトには例えば配列(Array)がありますが、それ以外にもいくつかあります。
また、反復可能オブジェクトは自分で作ることもできます。(詳細

できること

制御文が使える

forof文ではbreakcontinueが使えます。

それぞれの文の動作は大体こんな感じです。

  • break: ループ全体を中断する
  • continue: 次のループに行く
for (const num of [1, 4, 5] {
  // 偶数だったら次のループに行く
  if (num % 2 === 0) continue
  console.log(num)
}

// 1
// 5

関数の戻り値が決められる

関数内で使う場合、その関数の戻り値を決めるためにreturnが使えます。

例えば、以下の動作をするsumEven関数を楽に定義できます。

  • 配列の要素が偶数の間合計し続ける
  • 奇数があったらその時点の合計を返す
function sumEven(array) {
  let sum = 0
  for (const num of array) {
    if (num % 2 !== 0) return sum // 奇数の場合
    sum += num
  }
  return sum // 全ての数が偶数だった場合
}

これをforEachで実装する場合、一手間必要になります。
一番簡単なのはフラグを用意する方法でしょうか。

function sumEven(array) {
  let sum = 0
  let flag = false // 奇数の値がすでに出現したかどうか
  array.forEach(num => {
    if (flag) return // フラグがtrueなら何も足さない
    if (num % 2 !== 0) { // 奇数の場合
      flag = true
      return
    }
    sum += num
  })
  return sum // 全ての数が偶数だった場合
}

できないこと

インデックスを使うには一手間必要

forof文でインデックスを用いたループをしたい場合、配列のentriesメソッドを使う必要があります。

const array = ['A', 'B', 'C']
// (const [インデックスの変数名, 値の変数名] of 配列名.entries())
for (const [index, value] of array.entries()) {
  console.log(`No. ${index}: ${value}`)
}

// No. 0: A
// No. 1: B
// No. 2: C

配列のentriesメソッドは、[インデックス, 値]という形式の値を持つ反復可能オブジェクトを返します。
詳細はMDNをご覧ください。

制御文とforEach

returncontinue

forEachreturnforofcontinueは、実質的に同じように動きます。

  • forEachreturn: 今の関数の実行を終わり、次のループに行く
  • forofcontinue: 今回のループを終わり、次のループに行く

それ以外

それ以外の制御文は、forEachに対応するものはありません。

  • forofbreak: forEachではできない
  • 関数内でのforofreturn: forEachではできない

forEachbreakしたくなった場合、代わりにforofを使うのが一番わかりやすくて良い選択肢でしょう。

1
0
4

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?