【JavaScript】throw で forEach 中でもどこでも break

 こんなことしない方が読みやすいコードになるのですが JavaScript ではこんなこともできる、ということを紹介します。
 よく JavaScript で散見される質問に forEach 中で break する方法、というものがあります。for を知っていて forEach を使い始めるとよく何故 break がないのか、となります(なんとなくですが制御構造として foreach が組み込まれている言語は break できて、配列やリストなどのメソッドとして組み込まれている言語は元となるクラスが言語組み込みクラスであっても break できない気がします)。
 具体的なコードとデモは次です。

/**
 * 負の値を先頭から順に探す関数
 */
function findMinusNumber(numberList){
  try{
    // forEach を実行
    numberList.forEach(item=>{
      if(item < 0){
          throw item;// throw で現在参照中のアイテムを投げる
      }
    })
  }catch(minusNumber){
    // throw された値をキャッチ。Error オブジェクトでなくてもOK
    if(typeof minusNumber === 'number'){
      return minusNumber; // throw された値を return;
    }
  }
  return null;
}


 JavaScript の throw は例のコードの様に例外オブジェクト(PHP や Python の Exception, MATLAB の MException)相当である Error 以外も投げることができます。ドキュメントを見る限り throw されたものこそが例外である、といった感じです。
throw – JavaScript | MDN
 そして throw は

現在の関数の実行は停止し (throw の後の文は実行されません)、コールスタック内の最初の catch ブロックに制御を移します。
throw – JavaScript | MDN

とある様に処理を停止させて catch までに処理を飛ばします。
 この二つにより任意の場所で処理を停止させて好きな値を停止箇所の呼び出し側コードの任意の場所に渡せます。

 この様なことができるとはいえ throw を break や強力な return の様に使うのはなるべく避けた方が良いです。例外処理はコードを追いにくくし、また例外処理は関数の異常終了を示すという多くの人が思っているであろう共通認識を崩すこととなり、コードを読みにくく、理解しにくくします。
 forEach + break で行いたいことには大体、代替となるメソッドがあります。何かを見つけるならば find, 元配列の個数を元に処理を打ち切りたいのであれば slice といった具合です。
 また次の様に forEach 的なメソッドによるループでなく for of を使うのもよいです。

/**
 * 負の値を先頭から順に探す関数
 */
function findMinusNumber(numberList){
  let minusNumber = null;
  for (item of numberList) {
    if(item < 0){
      minusNumber = item;
      break;// throw で現在参照中のアイテムを投げる
    }
  }
  return minusNumber;
}
>株式会社シーポイントラボ

株式会社シーポイントラボ

TEL:053-543-9889
営業時間:9:00~18:00(月〜金)
住所:〒432-8003
   静岡県浜松市中央区和地山3-1-7
   浜松イノベーションキューブ 315
※ご来社の際はインターホンで「316」をお呼びください

CTR IMG