[1,2,3].forEach(function(el) {
if(el === 1) break;
});
Comment puis-je faire cela en utilisant la nouvelle méthode forEach
en JavaScript? J'ai essayé return;
, return false;
et break
. break
plante et return
ne fait que continuer l'itération.
Il n'y a pas de capacité intégrée à break
dans forEach
. Pour interrompre l'exécution, il faudrait lancer une exception. par exemple.
_var BreakException = {};
try {
[1, 2, 3].forEach(function(el) {
console.log(el);
if (el === 2) throw BreakException;
});
} catch (e) {
if (e !== BreakException) throw e;
}
_
Les exceptions JavaScript ne sont pas très jolies. Une boucle for
traditionnelle peut être plus appropriée si vous avez vraiment besoin de break
à l'intérieur.
Array#some
À la place, utilisez Array#some
:
_[1, 2, 3].some(function(el) {
console.log(el);
return el === 2;
});
_
Cela fonctionne parce que some
renvoie true
dès que l'un des rappels, exécuté dans l'ordre du tableau, renvoie true
, court-circuitant l'exécution du reste.
some
, son inverse every
(qui s'arrêtera sur un _return false
_), et forEach
sont toutes des méthodes ECMAScript Fifth Edition qui devront être ajoutées à _Array.prototype
_ sur les navigateurs où ils manquent.
Il existe maintenant un moyen encore meilleur de le faire dans ECMAScript2015 (alias ES6) en utilisant le nouveau for of loop . Par exemple, ce code n'imprime pas les éléments du tableau après le nombre 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;
}
}
De la docs:
pour ... dans et pour ... sur instructions: itérer sur quelque chose. La principale différence entre eux réside dans ce sur quoi ils reviennent. L'instruction for ... in effectue une itération sur les propriétés énumérables d'un objet, dans l'ordre d'insertion d'origine. L'instruction pour ... de effectue une itération sur les données définies par l'objet itérable.
Besoin de l'index dans l'itération? Vous pouvez utiliser Array.entries()
:
for (const [index, el] of arr.entries()) {
if ( index === 5 ) break;
}
Vous pouvez utiliser la méthode every :
[1,2,3].every(function(el) {
return !(el === 1);
});
ES6
[1,2,3].every( el => el !== 1 )
pour les anciens navigateurs, utilisez:
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;
};
}
plus de détails ici .
Citant le documentation MDN de Array.prototype.forEach()
:
Il n'y a aucun moyen d'arrêter ou de casser une boucle
forEach()
autrement qu'en lançant une exception. Si vous avez besoin d'un tel comportement, la méthode.forEach()
est le outil incorrect , utilisez plutôt une boucle simple. Si vous testez les éléments du tableau pour un prédicat et avez besoin d'une valeur de retour booléenne, vous pouvez utiliserevery()
ousome()
.
Pour votre code (dans la question), comme suggéré par @bobince, utilisez Array.prototype.some()
. Cela convient très bien à votre cas d'utilisation.
Array.prototype.some()
exécute la fonction de rappel une fois pour chaque élément présent dans le tableau jusqu'à ce qu'il en trouve un où le rappel renvoie une valeur de vérité (une valeur qui devient vraie lorsqu'elle est convertie enBoolean
). Si un tel élément est trouvé,some()
renvoie immédiatement la valeur true. Sinon,some()
renvoie false. callback n'est appelé que pour les index du tableau auxquels des valeurs ont été assignées; il n'est pas appelé pour les index qui ont été supprimés ou auxquels aucune valeur n'a été attribuée.
Malheureusement, dans ce cas, ce sera beaucoup mieux si vous n'utilisez pas forEach
. Utilisez plutôt une boucle normale for
et elle fonctionnera désormais exactement comme vous le souhaiteriez.
var array = [1, 2, 3];
for (var i = 0; i < array.length; i++) {
if (array[i] === 1){
break;
}
}
Pensez à utiliser la méthode jquery
de each
, car elle permet de renvoyer une fonction de rappel fausse à l'intérieur:
$.each(function(e, i) {
if (i % 2) return false;
console.log(e)
})
Les bibliothèques Lodash fournissent également la méthode takeWhile
pouvant être chaînée avec map/réduire/fold, etc.:
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');
// => []
Dans votre exemple de code, il apparaît que Array.prototype.find
est ce que vous recherchez: Array.prototype.find () et Array.prototype.findIndex ()
[1, 2, 3].find(function(el) {
return el === 2;
}); // returns 2
Si vous souhaitez utiliser suggestion de Dean Edward et lancer l'erreur StopIteration pour sortir de la boucle sans avoir à l'attraper, vous pouvez utiliser la fonction suivante ( originellement à partir d'ici ):
// 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;
}
}
};
}
})();
Le code ci-dessus vous permettra d'exécuter du code tel que celui-ci sans avoir à créer vos propres clauses 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);
});
Une chose importante à retenir est que cela ne mettra à jour la fonction Array.prototype.forEach que si elle existe déjà. S'il n'existe pas déjà, cela ne le modifiera pas.
Réponse courte: utilisez for...break
pour cela ou modifiez votre code pour éviter la rupture de forEach
. N'utilisez pas .some()
ou .every()
pour émuler for...break
. Réécrivez votre code pour éviter la boucle for...break
ou utilisez for...break
. Chaque fois que vous utilisez ces méthodes comme alternative à for...break
, Dieu tue le chaton.
Longue réponse:
.some()
et .every()
retournent tous deux boolean
value, .some()
renvoie true
s'il existe un élément pour lequel la fonction transmise retourne true
, chaque retourne false
s'il existe un élément pour lequel la fonction transmise est renvoyée false
. C'est ce que cela signifie. Utiliser des fonctions pour ce qu'elles ne veulent pas dire est bien pire que d'utiliser des tableaux pour la présentation au lieu de CSS, car cela frustre tout le monde qui lit votre code.
En outre, le seul moyen possible d'utiliser ces méthodes comme alternative à for...break
consiste à créer des effets secondaires (modifier certains vars en dehors de la fonction de rappel .some()
), ce qui n'est pas très différent de for...break
.
Donc, utiliser .some()
ou .every()
comme alternative à la boucle for...break
n'est pas exempt d'effets secondaires, ce n'est pas beaucoup plus propre que for...break
, c'est frustrant, donc ce n'est pas mieux.
Vous pouvez toujours réécrire votre code pour qu'il ne soit plus nécessaire d'utiliser for...break
. Vous pouvez filtrer array en utilisant .filter()
, vous pouvez diviser array en utilisant .slice()
et ainsi de suite, puis utiliser .forEach()
ou .map()
pour cette partie du tableau.
Un autre concept que je suis venu avec:
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(); }
});
Trouvé cette solution sur un autre site. Vous pouvez envelopper le forEach dans un scénario 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; }
Plus de détails ici: http://dean.edwards.name/weblog/2006/07/enum/
C’est juste quelque chose que j’ai imaginé pour résoudre le problème ... Je suis à peu près sûr que cela corrige le problème rencontré par le demandeur initial:
Array.prototype.each = function(callback){
if(!callback) return false;
for(var i=0; i<this.length; i++){
if(callback(this[i], i) == false) break;
}
};
Et ensuite vous l'appeleriez en utilisant:
var myarray = [1,2,3];
myarray.each(function(item, index){
// do something with the item
// if(item != somecondition) return false;
});
Renvoyer faux dans la fonction de rappel provoquera une pause. Faites-moi savoir si cela ne fonctionne pas réellement.
Si vous n'avez pas besoin d'accéder à votre tableau après l'itération, vous pouvez sortir en réglant la longueur du tableau sur 0. Si vous en avez toujours besoin après votre itération, vous pouvez le cloner à l'aide de slice.
[1,3,4,5,6,7,8,244,3,5,2].forEach(function (item, index, arr) {
if (index === 3) arr.length = 0;
});
Ou avec un clone:
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;
});
Ce qui est une bien meilleure solution que de jeter des erreurs aléatoires dans votre code.
Ceci est une boucle for, mais conserve la référence de l'objet dans la boucle, comme pour un forEach (), mais vous pouvez vous en sortir.
var arr = [1,2,3];
for (var i = 0, el; el = arr[i]; i++) {
if(el === 1) break;
}
Comme mentionné précédemment, vous ne pouvez pas rompre .forEach()
.
Voici une manière un peu plus moderne de faire un foreach avec ES6 Iterators. Vous permet d’avoir un accès direct à index
/value
lors d’une itération.
const array = ['one', 'two', 'three'];
for (const [index, val] of array.entries()) {
console.log('item:', { index, val });
if (index === 1) {
console.log('break!');
break;
}
}
Sortie:
item: { index: 0, val: 'one' }
item: { index: 1, val: 'two' }
break!
Si vous souhaitez conserver votre syntaxe forEach
, il s'agit d'un moyen de la maintenir efficace (bien qu'elle ne soit pas aussi efficace qu'une boucle for normale). Recherchez immédiatement une variable qui sait si vous souhaitez sortir de la boucle.
Cet exemple utilise une fonction anonyme pour créer un étendue de la fonction autour de la forEach
dont vous avez besoin pour stocker les informations done.
(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>
Mes deux centimes.
Encore une autre approche
var wageType = types.filter(function(element){
if(e.params.data.text == element.name){
return element;
}
});
console.dir(wageType);
Je le sais pas comme il faut. Ce n'est pas casser la boucle. C'est un jugad
let result = true;
[1, 2, 3].forEach(function(el) {
if(result){
console.log(el);
if (el === 2){
result = false;
}
}
});
J'utilise nullhack pour cela, il essaie d'accéder à la propriété de null
, qui est une erreur:
try {
[1,2,3,4,5]
.forEach(
function ( val, idx, arr ) {
if ( val == 3 ) null.NULLBREAK;
}
);
} catch (e) {
// e <=> TypeError: null has no properties
}
//
vous pouvez suivre le code ci-dessous qui fonctionne pour moi:
var loopStop = false;
YOUR_ARRAY.forEach(function loop(){
if(loopStop){ return; }
if(condition){ loopStop = true; }
});
Utilisez la fonction array.prototype.every
, qui vous fournit l’utilitaire pour interrompre la lecture en boucle. Voir exemple ici Documentation Javascript sur le réseau de développeurs Mozilla
Je préfère utiliser for in
var words = ['a', 'b', 'c'];
var text = '';
for (x in words) {
if (words[x] == 'b') continue;
text += words[x];
}
console.log(text);
for in
fonctionne beaucoup comme forEach
, et vous pouvez ajouter la fonction return to exit à l'intérieur. Meilleure performance aussi.
Ce n’est pas le plus efficace, car vous devez toujours parcourir tous les éléments, mais j’ai pensé que cela valait la peine d’envisager le très simple:
let keepGoing = true;
things.forEach( (thing) => {
if (noMore) keepGoing = false;
if (keepGoing) {
// do things with thing
}
});
essayez avec "trouver":
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" }
D'accord avec @bobince, voté.
Aussi, FYI:
Prototype.js a quelque chose à cette fin:
<script type="text/javascript">
$$('a').each(function(el, idx) {
if ( /* break condition */ ) throw $break;
// do something
});
</script>
$break
sera attrapé et traité par Prototype.js en interne, interrompant le cycle "chaque" mais ne générant pas d'erreurs externes.
Voir API Prototype.JS pour plus de détails.
jQuery a aussi un moyen, il suffit de retourner false dans le gestionnaire pour rompre la boucle plus tôt:
<script type="text/javascript">
jQuery('a').each( function(idx) {
if ( /* break condition */ ) return false;
// do something
});
</script>
Voir API jQuery pour plus de détails.
Si vous devez effectuer une rupture en fonction de la valeur des éléments déjà présents dans votre tableau, comme dans votre cas (c.-à-d. Si la condition de rupture ne dépend pas de la variable d'exécution susceptible de changer après que le tableau a reçu la valeur de ses éléments), vous pouvez également utiliser la combinaison de slice () et indexOf () comme suit.
Si vous avez besoin de faire une pause quand forChaque atteint 'Apple', vous pouvez utiliser
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
});
Comme indiqué dans W3Schools.com la méthode slice () renvoie les éléments sélectionnés dans un tableau, en tant que nouvel objet tableau. Le tableau d'origine ne sera pas modifié.
Voir dans JSFiddle
J'espère que ça aide quelqu'un.