[1,2,3].forEach(function(el) {
if(el === 1) break;
});
forEach
JavaScriptの新しいメソッドを使用してこれを行うにはどうすればよいですか?私は試しましたreturn;
、return false;
そしてbreak
。break
クラッシュしreturn
て何もせず、繰り返しを続ける。
[1,2,3].forEach(function(el) {
if(el === 1) break;
});
forEach
JavaScriptの新しいメソッドを使用してこれを行うにはどうすればよいですか?私は試しましたreturn;
、return false;
そしてbreak
。break
クラッシュしreturn
て何もせず、繰り返しを続ける。
回答:
何のビルトインする機能はありませんbreak
の中でforEach
。実行を中断するには、何らかの例外をスローする必要があります。例えば。
var BreakException = {};
try {
[1, 2, 3].forEach(function(el) {
console.log(el);
if (el === 2) throw BreakException;
});
} catch (e) {
if (e !== BreakException) throw e;
}
JavaScriptの例外はひどくきれいではありません。for
あなたが本当にbreak
それを中に入れる必要があるなら、伝統的なループはより適切かもしれません。
Array#some
代わりに、次を使用しますArray#some
。
[1, 2, 3].some(function(el) {
console.log(el);
return el === 2;
});
これが機能するのは、配列順に実行されるコールバックのいずれかがsome
戻るtrue
とすぐに戻りtrue
、残りの実行が短絡されるためです。
some
、その逆every
(これはで停止しますreturn false
)でありforEach
、ECMAScript Fifth EditionのすべてのメソッドArray.prototype
です。これらのメソッドは、存在しないブラウザーでに追加する必要があります。
some
そしてevery
、これは答えのTOPにあるはずです。なぜそれが読みにくいと思うのか理解できません。それはただ素晴らしいです!
Array#some
は本当にいいです。まず、ie9やfirefox 1.5を含むほとんどのブラウザーとの互換性も非常によく機能します。私の使用例は、数値が下限と上限のペアの間にあるrange [a、b]の配列でインデックスを見つけることです。見つかった場合、テストしてtrueを返します。for..of
次の最良のソリューションですが、新しいブラウザのみです。
ECMAScript2015(別名ES6)でこれを行うには、新しいforループを使用してさらに優れた方法があります。たとえば、次のコードは、数値5の後の配列要素を出力しません。
let arr = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
for (let el of arr) {
console.log(el);
if (el === 5) {
break;
}
}
ドキュメントから:
for ... inとfor ... ofの両方のステートメントで何かが繰り返されます。それらの主な違いは、何を繰り返すかです。以下のために...内のステートメントは、原稿挿入のためには、オブジェクトの列挙可能なプロパティを反復処理します。以下のために...のステートメントは、反復可能なオブジェクトの定義を繰り返し処理するというデータを反復処理します。
反復でインデックスが必要ですか?使用できますArray.entries()
:
for (const [index, el] of arr.entries()) {
if ( index === 5 ) break;
}
entries
。使用する必要があります。for(const [index、element] of someArray.entries()){// ...}
すべての方法を使用できます。
[1,2,3].every(function(el) {
return !(el === 1);
});
ES6
[1,2,3].every( el => el !== 1 )
古いブラウザサポートを使用する場合:
if (!Array.prototype.every)
{
Array.prototype.every = function(fun /*, thisp*/)
{
var len = this.length;
if (typeof fun != "function")
throw new TypeError();
var thisp = arguments[1];
for (var i = 0; i < len; i++)
{
if (i in this &&
!fun.call(thisp, this[i], i, this))
return false;
}
return true;
};
}
詳細はこちら。
[1,2,3].every( el => el !== 1 )
every
れることを保証しますか?
k
:0から始まり、1ずつインクリメントされるhttp://www.ecma-international.org/ecma-262/6.0/#sec-array.prototype.every
のMDNドキュメントArray.prototype.forEach()
からの引用:
例外をスローする以外にループを停止または解除する方法はありません
forEach()
。このような動作が必要な場合、.forEach()
メソッドは間違ったツールです。代わりに単純なループを使用してください。述語の配列要素をテストしていて、ブール戻り値が必要な場合は、every()
またはを使用できますsome()
。
@bobinceによって提案されているように、(質問の)コードにはArray.prototype.some()
代わりに使用してください。ユースケースに非常に適しています。
Array.prototype.some()
コールバックが真の値(に変換されたときに真になる値)を返す場所が見つかるまで、配列内の各要素に対してコールバック関数を1回実行しますBoolean
。そのような要素が見つかると、some()
すぐにtrueを返します。それ以外の場合は、some()
falseを返します。コールバックは、値が割り当てられている配列のインデックスに対してのみ呼び出されます。削除されたインデックス、または値が割り当てられていないインデックスに対しては呼び出されません。
残念ながら、この場合、を使用しない方がはるかに優れていますforEach
。代わりに、通常のfor
ループを使用すると、期待どおりに動作します。
var array = [1, 2, 3];
for (var i = 0; i < array.length; i++) {
if (array[i] === 1){
break;
}
}
jquery
のeach
メソッドを使用することを検討してください。コールバック関数内でfalseを返すことができるためです。
$.each(function(e, i) {
if (i % 2) return false;
console.log(e)
})
LodashライブラリはtakeWhile
、map / reduce / foldなどと連鎖できるメソッドも提供します:
var users = [
{ 'user': 'barney', 'active': false },
{ 'user': 'fred', 'active': false },
{ 'user': 'pebbles', 'active': true }
];
_.takeWhile(users, function(o) { return !o.active; });
// => objects for ['barney', 'fred']
// The `_.matches` iteratee shorthand.
_.takeWhile(users, { 'user': 'barney', 'active': false });
// => objects for ['barney']
// The `_.matchesProperty` iteratee shorthand.
_.takeWhile(users, ['active', false]);
// => objects for ['barney', 'fred']
// The `_.property` iteratee shorthand.
_.takeWhile(users, 'active');
// => []
あなたのコード例から、それはArray.prototype.find
あなたが探しているもののように見えます:Array.prototype.find()とArray.prototype.findIndex()
[1, 2, 3].find(function(el) {
return el === 2;
}); // returns 2
ディーン・エドワードの提案を使用し、StopIterationエラーをスローして、エラーをキャッチせずにループから抜け出す場合は、次の関数を使用できます(最初はここから)。
// Use a closure to prevent the global namespace from be polluted.
(function() {
// Define StopIteration as part of the global scope if it
// isn't already defined.
if(typeof StopIteration == "undefined") {
StopIteration = new Error("StopIteration");
}
// The original version of Array.prototype.forEach.
var oldForEach = Array.prototype.forEach;
// If forEach actually exists, define forEach so you can
// break out of it by throwing StopIteration. Allow
// other errors will be thrown as normal.
if(oldForEach) {
Array.prototype.forEach = function() {
try {
oldForEach.apply(this, [].slice.call(arguments, 0));
}
catch(e) {
if(e !== StopIteration) {
throw e;
}
}
};
}
})();
上記のコードを使用すると、独自のtry-catch句を実行しなくても、次のようなコードを実行できます。
// Show the contents until you get to "2".
[0,1,2,3,4].forEach(function(val) {
if(val == 2)
throw StopIteration;
alert(val);
});
覚えておくべき重要なことの1つは、Array.prototype.forEach関数が既に存在する場合にのみこれを更新することです。まだ存在しない場合は、変更されません。
短い答え:for...break
これを使用するか、コードを変更して、の破損を回避しますforEach
。.some()
または.every()
エミュレートするために使用しないでくださいfor...break
。for...break
ループを回避するようにコードを書き直すか、を使用してくださいfor...break
。for...break
代わりにこれらの方法を使用するたびに、神は子猫を殺します。
長い答え:
.some()
そして.every()
両方の戻りboolean
値は、.some()
リターンtrue
のための任意の要素は、関数が戻るが渡された場合true
、すべてのリターンfalse
のための任意の要素は、関数が戻るが渡された場合をfalse
。これがその機能の意味です。意味のないものに関数を使用することは、CSSの代わりにレイアウトにテーブルを使用するよりもはるかに悪いことです。なぜなら、コードを読むすべての人を苛立たせるからです。
また、これらのメソッドをfor...break
代替として使用する唯一の可能な方法は、副作用(.some()
コールバック関数の外部で一部の変数を変更する)を行うことであり、これはと大差ありませんfor...break
。
したがって、ループの代替として、.some()
または.every()
as を使用してもfor...break
副作用がありません。これはそれほどクリーンでfor...break
はありません。イライラするので、これは良くありません。
コードはいつでも書き換えることができるので、での必要はありませんfor...break
。を使用して配列をフィルタリングしたり.filter()
、配列を使用.slice()
して配列を分割し.forEach()
たり.map()
、配列のその部分にor を使用したりできます。
for...break
パフォーマンスが必要な場合はループを使用します。for
ループがより最もパフォーマンスの反復ツールである.forEach()
、.any()
、.map()
、.filter()
など
これは私が問題を解決するために思いついたものです...私はそれが元の質問者が持っていた問題を修正すると確信しています:
Array.prototype.each = function(callback){
if(!callback) return false;
for(var i=0; i<this.length; i++){
if(callback(this[i], i) == false) break;
}
};
そして、あなたはそれを使ってそれを呼び出すでしょう:
var myarray = [1,2,3];
myarray.each(function(item, index){
// do something with the item
// if(item != somecondition) return false;
});
コールバック関数内でfalseを返すと、ブレークが発生します。それが実際に機能しない場合はお知らせください。
=== false
== false
ループを続行するために明示的にtrue(または真の値)を返す必要がないので、いくつかの制御パスが値を返さず、ループが予期せず中断しないようにするよりも良いかもしれません。
私が思いついた別のコンセプト:
function forEach(array, cb) {
var shouldBreak;
function _break() { shouldBreak = true; }
for (var i = 0, bound = array.length; i < bound; ++i) {
if (shouldBreak) { break; }
cb(array[i], i, array, _break);
}
}
// Usage
forEach(['a','b','c','d','e','f'], function (char, i, array, _break) {
console.log(i, char);
if (i === 2) { _break(); }
});
Array.prototype.forEach()
ます。 for
そして、break
この質問が尋ねられるずっと前に存在しました。OPは、より機能的なを使用してその動作を探していましたforEach
。
for...in
およびで問題を解決できる場合は不要であると述べていますbreak
。
このソリューションは別のサイトで見つかりました。forEachをtry / catchシナリオでラップできます。
if(typeof StopIteration == "undefined") {
StopIteration = new Error("StopIteration");
}
try {
[1,2,3].forEach(function(el){
alert(el);
if(el === 1) throw StopIteration;
});
} catch(error) { if(error != StopIteration) throw error; }
反復後に配列にアクセスする必要がない場合は、配列の長さを0に設定することで救済できます。反復後にも必要な場合は、スライスを使用して複製できます。
[1,3,4,5,6,7,8,244,3,5,2].forEach(function (item, index, arr) {
if (index === 3) arr.length = 0;
});
またはクローンで:
var x = [1,3,4,5,6,7,8,244,3,5,2];
x.slice().forEach(function (item, index, arr) {
if (index === 3) arr.length = 0;
});
これは、コードでランダムなエラーをスローするよりもはるかに優れたソリューションです。
array.length
、0
それらは現在の反復で適用されるので、おそらくそのreturn
ような割り当ての後に使用する方が良い場合があります
前に述べたように、あなたは壊れることはできません.forEach()
。
ES6イテレーターでforeachを行うもう少しモダンな方法を次に示します。反復時にindex
/ value
に直接アクセスできるようにします。
const array = ['one', 'two', 'three'];
for (const [index, val] of array.entries()) {
console.log('item:', { index, val });
if (index === 1) {
console.log('break!');
break;
}
}
出力:
item: { index: 0, val: 'one' }
item: { index: 1, val: 'two' }
break!
私はその目的のためにnullhackを使用しますnull
、それはのプロパティにアクセスしようとしますが、これはエラーです:
try {
[1,2,3,4,5]
.forEach(
function ( val, idx, arr ) {
if ( val == 3 ) null.NULLBREAK;
}
);
} catch (e) {
// e <=> TypeError: null has no properties
}
//
throw BREAK
ですか?
維持したい場合 forEach
構文、これは効率を維持する方法です(ただし、通常のforループほど良くはありません)。ループを抜けたいかどうかがわかる変数をすぐに確認してください。
この例では、無名関数を使用して、完了した情報を格納する必要のある関数スコープを作成します。forEach
(function(){
var element = document.getElementById('printed-result');
var done = false;
[1,2,3,4].forEach(function(item){
if(done){ return; }
var text = document.createTextNode(item);
element.appendChild(text);
if (item === 2){
done = true;
return;
}
});
})();
<div id="printed-result"></div>
私の2セント。
array.prototype.every
ループを解除するユーティリティを提供する関数を使用します。Mozilla開発者ネットワークのJavascriptドキュメントの例を参照してください
@bobinceに同意する(賛成)。
また、参考までに:
Prototype.jsには、この目的のための何かがあります。
<script type="text/javascript">
$$('a').each(function(el, idx) {
if ( /* break condition */ ) throw $break;
// do something
});
</script>
$break
Prototype.jsが内部的にキャッチして処理するため、「各」サイクルは中断されますが、外部エラーは発生しません。
詳細については、Prototype.JS APIを参照してください。
jQueryにも方法があります。ループを早期に中断するには、ハンドラーでfalseを返すだけです。
<script type="text/javascript">
jQuery('a').each( function(idx) {
if ( /* break condition */ ) return false;
// do something
});
</script>
詳細については、jQuery APIを参照してください。
すべての要素を循環させるので、これは最も効率的ではありませんが、非常に単純なものを検討する価値があると思いました。
let keepGoing = true;
things.forEach( (thing) => {
if (noMore) keepGoing = false;
if (keepGoing) {
// do things with thing
}
});
continue
はキーワードです。コードは構文エラーです。
for of
ループに切り替えて、break;
通常どおりループから切り替える必要があります。
あなたは私のために働く以下のコードに従うことができます:
var loopStop = false;
YOUR_ARRAY.forEach(function loop(){
if(loopStop){ return; }
if(condition){ loopStop = true; }
});
あなたの場合のようにすでに配列にある要素の値に基づいて分割する必要がある場合(つまり、分割条件が、配列に要素値が割り当てられた後に変更される可能性があるランタイム変数に依存しない場合)、組み合わせを使用することもできます。以下のように、slice()およびindexOf()を使用します。
forEachが「Apple」に達したときに中断する必要がある場合は、
var fruits = ["Banana", "Orange", "Lemon", "Apple", "Mango"];
var fruitsToLoop = fruits.slice(0, fruits.indexOf("Apple"));
// fruitsToLoop = Banana,Orange,Lemon
fruitsToLoop.forEach(function(el) {
// no need to break
});
W3Schools.comで述べられているように、slice()メソッドは、配列内の選択された要素を新しい配列オブジェクトとして返します。元の配列は変更されません。
それが誰かを助けることを願っています。
あなたはのバリアント作成することができますforEach
することができますことをbreak
、continue
、return
、さらにはasync
/ await
(活字体で書かれた例):
export type LoopControlOp = "break" | "continue" | ["return", any];
export type LoopFunc<T> = (value: T, index: number, array: T[])=>LoopControlOp;
Array.prototype.ForEach = function ForEach<T>(this: T[], func: LoopFunc<T>) {
for (let i = 0; i < this.length; i++) {
const controlOp = func(this[i], i, this);
if (controlOp == "break") break;
if (controlOp == "continue") continue;
if (controlOp instanceof Array) return controlOp[1];
}
};
// this variant lets you use async/await in the loop-func, with the loop "awaiting" for each entry
Array.prototype.ForEachAsync = async function ForEachAsync<T>(this: T[], func: LoopFunc<T>) {
for (let i = 0; i < this.length; i++) {
const controlOp = await func(this[i], i, this);
if (controlOp == "break") break;
if (controlOp == "continue") continue;
if (controlOp instanceof Array) return controlOp[1];
}
};
使用法:
function GetCoffee() {
const cancelReason = peopleOnStreet.ForEach((person, index)=> {
if (index == 0) return "continue";
if (person.type == "friend") return "break";
if (person.type == "boss") return ["return", "nevermind"];
});
if (cancelReason) console.log("Coffee canceled because: " + cancelReason);
}
「見つける」で試してください:
var myCategories = [
{category: "start", name: "Start", color: "#AC193D"},
{category: "action", name: "Action", color: "#8C0095"},
{category: "exit", name: "Exit", color: "#008A00"}
];
function findCategory(category) {
return myCategories.find(function(element) {
return element.category === category;
});
}
console.log(findCategory("start"));
// output: { category: "start", name: "Start", color: "#AC193D" }
はい、forEachループを続行して終了できます。
続行するには、リターンを使用できます。ループは続行しますが、現在の関数は終了します。
ループを終了するには、3番目のパラメーターを長さ0に設定し、空の配列に設定します。ループは継続されず、現在の関数は継続するため、通常のforループの終了のように、「return」を使用して終了できます...
この:
[1,2,3,4,5,6,7,8,9,10].forEach((a,b,c) => {
console.log(a);
if(b == 2){return;}
if(b == 4){c.length = 0;return;}
console.log("next...",b);
});
これを印刷します:
1
next... 0
2
next... 1
3
4
next... 3
5
以前は、私のコードは以下です
this.state.itemsDataSource.forEach((item: any) => {
if (!item.isByPass && (item.invoiceDate == null || item.invoiceNumber == 0)) {
return false;
}
});
以下に変更しましたので修正しました。
for (var i = 0; i < this.state.itemsDataSource.length; i++) {
var item = this.state.itemsDataSource[i];
if (!item.isByPass && (item.invoiceDate == null || item.invoiceNumber == 0)) {
return false;
}
}
return
確かに反復を続けるん、それはブロックでそれの後に来る任意のコードをスキップします。次のコードを例にとり[1,2,3].forEach(function(el) { if(el === 2) { console.log(`Match on 2!`); return; } console.log(el); });
ます。.2console.log(el);
が一致するとスキップされます。