【JavaScript】 forEach()を中断させる一番スマートな方法
更新日:2021/07/30
forEach( )はJavaScriptの配列を列挙するメソッドです。
プログラムを書いていると、列挙中に処理を中断するケースは意外と多いものです。
しかしforEach( )は途中で中断できません。
では、どうすればいいのかをお伝えします。
forEach()は止まらない
ArrayオブジェクトのforEach()は、次のように要素を列挙できます。
const a = [ 1 , 2 , 3];
a.forEach( function (e){
console.log( e );
});
では、列挙中に中断したいときはどうしたらいいのでしょうか。
結論:中断できません。
forEachメソッドで行っている処理をザックリ書くと、次のようになります。
Array.prototype.forEach( callBack ){
const data = this.data;
for( let i = 0 ; i < data.length ; i ++ ){
callBack( data[i] );
}
}
forEach()は配列の要素を一つずつコールバック関数にわたしているだけです。
そのコールバックで何をやっているかについては関与していませんし、戻り値のチェックなども行っていません。
そのため、例外を発生させたり、配列の内容を変更させる以外で、止めることはできません。
配列の列挙を中断させる
配列の列挙を中断させる方法は、代表的なもので3つあります。
for文を使用する
forEach()を中断させるというタイトルから離れてしまいますが、列挙を中断させたいときはfor文の使用がおススメです。
ここで紹介している他の方法は、中断するという意図がわかり難いというのが理由です。
for文を中断
const array = [ 1 , 2 , 3];
const arrayLength =array.length;
for( let i = 0 ; i < arrayLength ; i ++ ){
console.log( array[i] );
if( array[i] === 2 ) break;
}
上の例では、配列の要素値が2のとき、breakでループを終了しています。
次のようにfor...of文でも列挙を中断できます。
for...of文を中断
const array = [ 1 , 2 , 3];
for( const value of array ){
console.log(value );
if( value=== 2 ) break;
}
ただしfor...of文はイテラブルなオブジェクトからデータを取得する構文です。
配列以外のオブジェクトも利用できることを理解したうえで使用する必要があります。
some()またはevery()を使用する
Arrayオブジェクトのsome()またはevery()を使用すると、列挙を中断することができます。
構文はforEach()と同じですが、次の点が異なります。
some():
配列中に条件に一致するデータがあるか判断するメソッド。
一致するものがあればtrue。なければfalseを返す。
※ようするにコールバック関数がtrueをリターンするまでループする。
every():
配列中にデータ全てが、条件に一致するかどうか判断するメソッド。
全て一致すればtrue。一つでも一致しないならfalseを返す。
※ようするにコールバック関数がfalseをリターンするまでループする
それぞれ本来の使用目的はforEach()と異なります。
しかしアルゴリズム上の動作を利用して、列挙を中断させることが可能です。
some()とevery()の仕様はこちらをご覧ください。
■22.1.3.26 Array.prototype.some ( callbackfn [ , thisArg ] )
■22.1.3.5 Array.prototype.every ( callbackfn [ , thisArg ] )
some()での列挙中断例
const a = [ 1 , 2 , 3];
a.some( function (e){
console.log( e );
return e === 2 ? true : false; // return e === 2; でもよい
});
上の例の3項演算子 e === 2 ? true : false; は、e === 2と省略することができます。ここでは、trueまたはfalseをリターンしているという意味を込めて3項演算子にしてあります。
上の例を実行すると配列aの要素2のコールバックが呼び出された後、some()の処理が終了します。
つまり要素3が呼び出されずに、中断したことになります。
forEach()をそのまま変更すればいいので、お手軽ですね。
every()の例も見ていきます。
戻り値を反転させるだけです。
every()での列挙中断例
const a = [ 1 , 2 , 3];
a.every( function (e){
console.log( e );
return e === 2 ? false : true; // return e !== 2; でもよい
});
配列の長さを書き換える
元になる配列のlengthプロパティを書き換えることで、列挙を中断できます。
配列のlengthプロパティを書き換えて中断
const a = [ 1 , 2 , 3];
a.forEach( function (e,index,array){
console.log( e );
if( e === 2 ) array.length = index + 1;
});
配列のlengthを変更すると、それ以降の配列の要素が削除されます。
forEachメソッドは変更前の長さでループを続行しますが、配列内に要素インデックスが存在しないため、コールバック関数が呼び出されません。
つまり表面上は中断していますが、内部ではループしています。
この方法は、配列の内容を書き換えてしまいます。
列挙を中断させためだけに配列を書き換えるのは、少し強引ですね。
まとめ
当初は列挙を途中で中断するならsome()やevery()を使用できます、というお話でした。
しかし、素直にfor文を使用したほうが、意図がわかりやすいと感じるようになりました。
一番スマートな方法ではありませんでしたね。
更新日:2021/07/30
関連記事
スポンサーリンク
記事の内容について
こんにちはけーちゃんです。
説明するのって難しいですね。
「なんか言ってることおかしくない?」
たぶん、こんなご意見あると思います。
裏付けを取りながら記事を作成していますが、僕の勘違いだったり、そもそも情報源の内容が間違えていたりで、正確でないことが多いと思います。
そんなときは、ご意見もらえたら嬉しいです。
掲載コードについては事前に動作確認をしていますが、貼り付け後に体裁を整えるなどをした結果動作しないものになっていることがあります。
生暖かい視線でスルーするか、ご指摘ください。
ご意見、ご指摘はこちら。
https://note.affi-sapo-sv.com/info.php
このサイトは、リンクフリーです。大歓迎です。