underscore.jsの_.each関数を壊す方法


200

underscore.js _.each()メソッドの反復を停止する方法を探していますが、解決策が見つかりません。そうするとjQuery .each()が壊れる可能性がありますreturn false

各アンダースコアを停止する方法はありますか?

_([1,2,3]).each(function(v){
    if (v==2) return /*what?*/;
})

4
ネイティブforEach関数もこの機能を提供していないので、それは可能ではないと思います。
Felix Kling

8
通常、each(ほとんどの言語で)クロージャーと一緒に使用する場合、最初にリストをフィルタリングする必要があります。そうすれば、それから脱却することを心配する必要はありません。一般的に言って、イテレーションから早期にブレークする必要がある場合、おそらく別の方法でそれを行うことができます。
Rob Hruska、2012年

次に 、Groovyに関するいくつかの関連する質問eachを示します。ここで、動作(クロージャーから都合よく中断できないこと)はJavaScriptに似ています。
Rob Hruska、2012年

@Dmitry_F、他の人が指摘したように、あなたが求めていることを正確に行うことはできません。しかし、私が示したように、あなたはArray.everyあなたが望む振る舞いをエミュレートするために使うことができます。
aeskr 2012年

@ロブ。乾杯。最初のコメントは本当に役に立ちました。確かに、私にはそれを行うことができたはずの別の方法がありました。
net.uk.sweet

回答:


267

メソッドから抜けることはできません。eachネイティブforEachメソッドは動作をエミュレートし、ネイティブforEachはループをエスケープする機能を備えていません(例外をスローする以外)。

しかし、すべての希望が失われるわけではありません!あなたは使うことができますArray.everyメソッド。:)

そのリンクから:

every提供されたcallback関数を、配列に存在する各要素に対して1回実行します。callback偽の値を返すます。そのような要素が見つかると、everyメソッドはすぐにfalseを返します。

つまり、このような複雑なことを行うことができます(JSFiddleへのリンク))。

[1, 2, 3, 4].every(function(n) {
    alert(n);
    return n !== 3;
});

これは警告します 1介してし3、ループから抜け出します。

あなたはunderscore.jsを使用しているので、それeveryメソッドを提供することを知って嬉しく思います—彼らはそれをと呼びますeveryが、そのリンクが言及するように、彼らはと呼ばれるエイリアスも提供しますall


2
underscore.jsはこれも実装していますか?
Felix Kling、2012年

1
@FelixKling、そうです。私はそれを私の答えに追加しました。
aeskr 2012年

2
現在(2013年5月)、アンダースコアの配列のメソッド_.every()_.all()メソッドもありません-に固執してくださいArray.every()
pkyeck 2013年

3
これは機能しますが、を使用する通常の理由ですevery。したがって、読みやすさに注意してください。
evanrmurphy 2014年

3
のアンダースコアドキュメントに_.each()は、ループから抜け出すことができないという事実に関する具体的な注記があり、_.find()代わりに使用することをお勧めします。 http://underscorejs.org/#each
blatt

70

更新:

_.findは、要素が見つかったときにループから抜けるため、より優れています。

var searchArr = [{id:1,text:"foo"},{id:2,text:"bar"}];
var count = 0;
var filteredEl = _.find(searchArr,function(arrEl){ 
              count = count +1;
              if(arrEl.id === 1 ){
                  return arrEl;
              }
            });

console.log(filteredEl);
//since we are searching the first element in the array, the count will be one
console.log(count);
//output: filteredEl : {id:1,text:"foo"} , count: 1

**古い**

条件付きでループから抜け出す場合は、_。eachではなく_.filter apiを使用します。ここにコードスニペットがあります

var searchArr = [{id:1,text:"foo"},{id:2,text:"bar"}];
var filteredEl = _.filter(searchArr,function(arrEl){ 
                  if(arrEl.id === 1 ){
                      return arrEl;
                  }
                });
console.log(filteredEl);
//output: {id:1,text:"foo"}

1
これはループを壊さない-それは単に配列をフィルタリングするだけです。配列に2つではなく20.000の項目があると想像してください。ログには、投稿した例のみが出力されますが、ループは20.000回実行されます:(
pkyeck

@pkyeckあなたは正しい、かもしれません_.findは_.filterより優れているかもしれません。elemntが見つかった後に壊れるので、これがフィドルです:jsfiddle.net/niki4810/9K3EV
Nikhil

2
この答えは正しいものとしてマークされるべきだと思います。_.find要求されたとおりのことを行いますtrue。コールバックが返されるまでリストを繰り返します。
Fabien Quatravaux 2013

受け入れられた回答(Array.every)はオブジェクトに対して機能しないため、この回答に投票しましたが、_。find()は機能します。
マット2013

そして、それがドキュメントで推奨されていることです。各ループを分離することはできないことに注意してください。中断するには、代わりに_.findを使用してください。
shaharsol 2014年

15

_.some代わりにあなたが見ることができます_.each_.some述語が真になると、リストの走査を停止します。結果は外部変数に保存できます。

_.some([1, 2, 3], function(v) {
    if (v == 2) return true;
})

http://underscorejs.org/#someを参照してください



3

アンダースコアのany()またはfind()が必要な場合があります。これらは条件が満たされたときに処理を停止します。



3

forEachEは、EcmaScript 5のネイティブの動作をエミュレートするため、アンダースコアで区切ることはできません。


2

配列が実際にオブジェクトである場合、空のオブジェクトを使用して返すことができると思います。

_.({1,2,3,4,5}).each(function(v){  
  if(v===3) return {}; 
});

これは、EcmaScript v <5でのみ発生します。これは、提供されたforEachの代替で空のオブジェクトを返すかどうかを確認するためにアンダースコアが行う比較は、ネイティブオブジェクトが使用できない場合にのみ行われるためです。
Alfonso de la Osa


1

更新:

内部でエラーをスローし、それを外部でキャッチすることで、実際に「ブレーク」できます。次のようなものです。

try{
  _([1,2,3]).each(function(v){
    if (v==2) throw new Error('break');
  });
}catch(e){
  if(e.message === 'break'){
    //break successful
  }
}

これは明らかに、コードがループでトリガーする他の例外に関して何らかの影響があるため、注意して使用してください!


私がこれに非常に多くの
反対

1
私はパーティーに遅れましたが、男はあなたが提案したことを言っただけでなく、さらに2つの選択肢を提供した(そしてより適切な)ことに注意してください。唯一の「ハック」は、ユーザーがどうしても必要な場合に備えて提供されます。代わりに、醜いハックのみを提供しました。
Areks

0

私の場合に働いた

var arr2 = _.filter(arr, function(item){
    if ( item == 3 ) return item;
});
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.