ECMA / Javascript Array.prototype.forEach
-
09-10-2019 - |
Question
Javascript (ECMAScript) prend en charge la méthode Array.prototype.forEach
depuis la version 1.6 (édition 3 ECMAScript, 2005). Donc, beaucoup de navigateur déjà soutenir cette méthode et il est incroyablement rapide par rapport à la méthode $.each()
jQuery par exemple.
(En fait, il bat toutes les implémentations, quelle que soit quelle bibliothèque Javascript)
Par rapport à jQuery, il est environ 60-70% plus rapide. Essayez-vous sur forEach vs jQuery sur JSPerf.
Le seul inconvénient que je l'ai jusqu'à présent l'utiliser est, je ne peux pas trouver un moyen de briser l'itération précoce. Comme for
, while
et do-while
ont une déclaration de break
, jQuerys .each()
soutient les return false
pour briser la boucle.
J'ai regardé dans les ECMAScript Edition 5 Spécifications (dernière je trouve), mais ils ne mentionnent pas une rupture anticipée de cette boucle.
Alors, la question, ce que M. Douglas Crockford appeler cela un design error
Suis-je manque quelque chose et il est possible de briser une telle boucle précoce?
Modifier
Merci pour les réponses à ce jour. Je suppose que puisque personne est venu avec une solution « native », il n'y a vraiment pas de mise en œuvre pour que (peut-être une fonctionnalité?). Quoi qu'il en soit, je ne sais vraiment pas comme les méthodes proposées donc je dupé autour d'un peu et a finalement trouvé que je aime (au moins, mieux). On dirait:
var div = document.createElement('div'),
divStyle = div.style,
support = jQuery.support,
arr = ['MozTransform', 'WebkitTransform', 'OTransform'];
arr.slice(0).forEach(function(v,i,a){
if(divStyle[v] === ''){
support.transform = v;
a.length = 0;
}
});
est le code de production "réel". Je cherchais un moyen agréable de rechercher la css3 propriétés de transformation et je me suis perdu dans les specs de ecma5 et étranges forums Javascript: -)
Ainsi, vous pouvez passer l'objet de tableau lui-même en tant que troisième paramètre dans la fonction de rappel de .forEach
. Je crée une copie du tableau original, appelant slice(0)
et définir sa propriété .length
à 0 dès que j'ai trouvé ce que je cherche. Fonctionne très bien.
Si quelqu'un arrive avec une meilleure solution que je vais modifier cela bien sûr.
La solution
Eh bien, vous pouvez utiliser every
à la place. La fonction est conçue pour revenir true
si le retour de la fonction de rappel fournie true
(truthy) pour chaque élément dans le tableau, et false
autrement. Point clé ici est qu'une fois la fonction de rappel retourne une valeur falsly, every
retourne sans false
immediat itérer sur le reste du tableau. Donc ignorer la valeur de retour, et traiter every
comme si elle était forEach
.
[1, 2, 3, 4, 5].every(function(e) {
alert(e);
if (e > 2) return false; //break
return true;
});
Dans cet exemple, alert
ne se déclenche 3 fois.
Bien sûr, le grand Cavet ici est que vous devez retourner une valeur truthy si vous voulez que la boucle pour continuer. En fait, si vous revenez rien (non défini) la boucle s'arrête. Alternativly, vous pouvez utiliser some
qui se comporte de la manière exactement inverse; retourne vrai lorsque la immediat fonction de rappel retourne une valeur truthy et fausse si elle ne fait jamais. Dans ce cas, return true
serait votre déclaration « break ». Oui Backwards, mais il vous évite d'avoir à return true
simplement avoir la boucle continue.
Maintenant, si vous concerened avec des performances, je voudrais recomend juste en utilisant une boucle de for
normale, car il y a les frais généraux importants encourus lors de l'appel functionas qui ajouteront très rapidement avec des tableaux plus grands. L'utilisation des fonctions natives aide un peu, mais les frais généraux des appels répétés à des fonctions définies par l'utilisateur existe toujours et est non négligeable. Au moins cela a été mon expérience, vous devez bien sûr faire vos propres tests.
Autres conseils
Vous pourriez jeter une erreur de sortir de l'itération:
if (typeof BreakIteration == "undefined") {
BreakIteration = new Error("BreakIteration");
}
try {
[0,1,2,3,4].forEach(function(key, value) {
console.log(key + ': ' + value);
if (value == 3) {
throw BreakIteration;
}
});
} catch (error) {
if (error !== BreakIteration) {
throw error;
}
}
Ce n'est pas exactement jolie. Je suis d'accord - bug spec
. Je suppose que vous avez un morceau de code qui doit être exécuté contre chaque élément. Ne pas utiliser forEach
pour trouver un élément ou même les opérations « arrêter au milieu ». Appliquer cette fonction à chaque élément dans un tableau.
Vous pourriez (je pense) utiliser une sorte d'indicateur global pour vérifier et faux retour si « trouvé » ou quelque chose.
var found = false;
array.forEach(function (k, v) {
if (found)
{
return false;
}
else
{
if (v == 1)
{
found = true;
}
}
});
Je pense que j'utiliser une autre construction si je veux faire une boucle de recherche.
Une option pour sortir du forEach-ing est bien sûr de quelque chose throw
, mais il est pas vraiment une façon voudrait utiliser un jet ...