Je l'ai cherché, mais je l'ai cherché forEach et pas seulement for. comme indiqué, en c # c'était un peu différent, et ça m'a dérouté :)
Dante1986
6
ECMAScript & nbsp; 6 contiendra peut-être la construction "for ... of". Voir pour ... de (MDN) pour plus d'informations. Vous pouvez déjà l'essayer avec les versions récentes de Firefox.
En revanche, en Python, il est plus efficace d'utiliser des fonctions que d'utiliser des boucles traditionnelles. (Considérez cela i < lenet cela i++peut être fait par le moteur, plutôt que par l'interprète.)
joeytwiddle
Réponses:
7023
TL; DR
Ne l'utilisez pas for-insauf si vous l'utilisez avec des garanties ou si vous savez au moins pourquoi il pourrait vous mordre.
JavaScript a une sémantique puissante pour parcourir les tableaux et les objets de type tableau. J'ai divisé la réponse en deux parties: les options pour les tableaux authentiques et les options pour les choses qui sont juste comme des tableaux , comme l' argumentsobjet, d'autres objets itérables (ES2015 +), les collections DOM, etc.
Je noterai rapidement que vous pouvez utiliser les options ES2015 maintenant , même sur les moteurs ES5, en transposant ES2015 en ES5. Recherchez "ES2015 transpiling" / "ES6 transpiling" pour en savoir plus ...
D'accord, regardons nos options:
Pour les tableaux réels
Vous avez trois options dans ECMAScript 5 ("ES5"), la version la plus largement prise en charge pour le moment, et deux autres ajoutées dans ECMAScript 2015 ("ES2015", "ES6"):
Utilisation forEachet connexes (ES5 +)
Utilisez une forboucle simple
Utiliser for-incorrectement
Utiliser for-of(utiliser un itérateur implicitement) (ES2015 +)
Utiliser explicitement un itérateur (ES2015 +)
Détails:
1. Utilisation forEachet connexes
Dans tout environnement vaguement moderne (donc pas IE8) où vous avez accès aux Arrayfonctionnalités ajoutées par ES5 (directement ou à l'aide de polyfills), vous pouvez utiliser forEach( spec| MDN):
var a =["a","b","c"];
a.forEach(function(entry){
console.log(entry);});
forEachaccepte une fonction de rappel et, éventuellement, une valeur à utiliser comme thislors de l'appel de ce rappel (non utilisé ci-dessus). Le rappel est appelé pour chaque entrée du tableau, dans l'ordre, en ignorant les entrées inexistantes dans les tableaux clairsemés. Bien que j'aie utilisé un seul argument ci-dessus, le rappel est appelé avec trois: la valeur de chaque entrée, l'index de cette entrée et une référence au tableau que vous parcourez (au cas où votre fonction ne l'aurait pas déjà à portée de main) ).
À moins que vous ne preniez en charge des navigateurs obsolètes comme IE8 (que NetApps affiche avec un peu plus de 4% de part de marché au moment de la rédaction de cet article en septembre 2016), vous pouvez utiliser avec plaisir forEachune page Web à usage général sans cale. Si vous devez prendre en charge des navigateurs obsolètes, le calage / polyfilling forEachse fait facilement (recherchez "shim es5" pour plusieurs options).
forEach a l'avantage que vous n'avez pas à déclarer les variables d'indexation et de valeur dans la portée contenante, car elles sont fournies en tant qu'arguments à la fonction d'itération, et si bien étendues à cette itération.
Si vous vous inquiétez du coût d'exécution d'un appel de fonction pour chaque entrée de tableau, ne le soyez pas; détails .
De plus, forEachest la fonction "boucle à travers tous", mais ES5 a défini plusieurs autres fonctions utiles "travaillez à travers le tableau et faites des choses", y compris:
every(arrête de boucler la première fois que le rappel revient falseou quelque chose de faux)
some(arrête de boucler la première fois que le rappel revient trueou quelque chose de vrai)
filter(crée un nouveau tableau comprenant des éléments où la fonction de filtre revient trueet en omettant ceux où elle revient false)
map (crée un nouveau tableau à partir des valeurs renvoyées par le rappel)
reduce (construit une valeur en appelant à plusieurs reprises le rappel, en passant les valeurs précédentes; voir la spécification pour les détails; utile pour additionner le contenu d'un tableau et bien d'autres choses)
reduceRight(comme reduce, mais fonctionne dans l'ordre décroissant plutôt que croissant)
2. Utilisez une forboucle simple
Parfois, les anciennes méthodes sont les meilleures:
var index;var a =["a","b","c"];for(index =0; index < a.length;++index){
console.log(a[index]);}
Si la longueur du tableau ne change pas pendant la boucle, et qu'il est en code sensible aux performances (peu probable), une version légèrement plus compliquée saisissant la longueur à l'avant pourrait être un tout petit peu plus rapide:
var index, len;var a =["a","b","c"];for(index =0, len = a.length; index < len;++index){
console.log(a[index]);}
Mais avec les moteurs JavaScript modernes, il est rare que vous ayez besoin de retirer ce dernier morceau de jus.
Dans ES2015 et supérieur, vous pouvez rendre vos variables d'index et de valeur locales à la forboucle:
let a =["a","b","c"];for(let index =0; index < a.length;++index){let value = a[index];
console.log(index, value);}//console.log(index); // would cause "ReferenceError: index is not defined"//console.log(value); // would cause "ReferenceError: value is not defined"
let a =["a","b","c"];for(let index =0; index < a.length;++index){let value = a[index];
console.log(index, value);}try{
console.log(index);}catch(e){
console.error(e);// "ReferenceError: index is not defined"}try{
console.log(value);}catch(e){
console.error(e);// "ReferenceError: value is not defined"}
Et lorsque vous faites cela, non seulement valuemais aussi indexest recréé pour chaque itération de boucle, ce qui signifie que les fermetures créées dans le corps de la boucle gardent une référence au index(et value) créé pour cette itération spécifique:
let divs = document.querySelectorAll("div");for(let index =0; index < divs.length;++index){
divs[index].addEventListener('click', e =>{
console.log("Index is: "+ index);});}
let divs = document.querySelectorAll("div");for(let index =0; index < divs.length;++index){
divs[index].addEventListener('click', e =>{
console.log("Index is: "+ index);});}
Si vous aviez cinq divisions, vous obtiendrez "Index is: 0" si vous avez cliqué sur le premier et "Index is: 4" si vous avez cliqué sur le dernier. Cela ne fonctionne pas si vous utilisez varau lieu de let.
3. Utilisez for-incorrectement
Vous aurez des gens qui vous disent d'utiliser for-in, mais ce n'est pas ce qui for-inest pour . for-inparcourt les propriétés énumérables d'un objet , pas les index d'un tableau. La commande n'est pas garantie , pas même en ES2015 (ES6). ES2015 + ne définit un ordre de propriétés de l' objet (via [[OwnPropertyKeys]], [[Enumerate]]et les choses qui les utilisent comme Object.getOwnPropertyKeys), mais il n'a pas précisé que for-insuivraient cet ordre; Mais ES2020 l'a fait. (Détails dans cette autre réponse .)
Les seuls cas d'utilisation réels pour for-inun tableau sont:
Vous utilisez des propriétés non-éléments et vous souhaitez les inclure dans la boucle
En ne regardant que ce premier exemple: vous pouvez utiliser for-inpour visiter ces éléments de tableau clairsemés si vous utilisez des protections appropriées:
// `a` is a sparse arrayvar key;var a =[];
a[0]="a";
a[10]="b";
a[10000]="c";for(key in a){if(a.hasOwnProperty(key)&&// These checks are/^0$|^[1-9]\d*$/.test(key)&&// explained
key <=4294967294// below){
console.log(a[key]);}}
Que l'objet a sa propre propriété de ce nom (pas celle qu'il hérite de son prototype), et
Que la clé est composée de chiffres décimaux (par exemple, une chaîne de caractères normale et non une notation scientifique), et
Que la valeur de la clé lorsqu'elle est contrainte à un nombre est <= 2 ^ 32 - 2 (qui est 4 294 967 294). D'où vient ce chiffre? Cela fait partie de la définition d'un index de tableau dans la spécification . Les autres nombres (non entiers, nombres négatifs, nombres supérieurs à 2 ^ 32 - 2) ne sont pas des index de tableau. La raison pour laquelle c'est 2 ^ 32 - 2 est que cela fait que la plus grande valeur d'index est inférieure à 2 ^ 32 - 1 , qui est la valeur maximale qu'un tableau lengthpeut avoir. (Par exemple, la longueur d'un tableau tient dans un entier non signé 32 bits.) (Props à RobG pour avoir souligné dans un commentaire sur mon blog que mon test précédent n'était pas tout à fait correct.)
Vous ne feriez pas cela en code intégré, bien sûr. Vous écririez une fonction utilitaire. Peut-être:
// Utility function for antiquated environments without `forEach`var hasOwn =Object.prototype.hasOwnProperty;var rexNum =/^0$|^[1-9]\d*$/;function sparseEach(array, callback, thisArg){var index;for(var key in array){
index =+key;if(hasOwn.call(a, key)&&
rexNum.test(key)&&
index <=4294967294){
callback.call(thisArg, array[key], index, array);}}}var a =[];
a[5]="five";
a[10]="ten";
a[100000]="one hundred thousand";
a.b ="bee";
sparseEach(a,function(value, index){
console.log("Value at "+ index +" is "+ value);});
Sous les couvertures, qui obtient un itérateur du tableau et boucle à travers lui, obtenant les valeurs de celui-ci. Cela n'a pas le problème que l'utilisation for-ina, car il utilise un itérateur défini par l'objet (le tableau), et les tableaux définissent que leurs itérateurs parcourent leurs entrées (et non leurs propriétés). Contrairement for-inà ES5, l'ordre dans lequel les entrées sont visitées est l'ordre numérique de leurs index.
5. Utilisez explicitement un itérateur (ES2015 +)
Parfois, vous souhaiterez peut-être utiliser explicitement un itérateur . Vous pouvez aussi le faire, même si c'est beaucoup plus maladroit que . Cela ressemble à ceci:for-of
const a =["a","b","c"];const it = a.values();let entry;while(!(entry = it.next()).done){
console.log(entry.value);}
L'itérateur est un objet correspondant à la définition de l'itérateur dans la spécification. Sa nextméthode retourne un nouvel objet résultat chaque fois que vous l'appelez. L'objet résultat a une propriété, donenous indiquant si c'est fait, et une propriété valueavec la valeur de cette itération. ( doneest facultatif s'il le serait false, valueest facultatif s'il le serait undefined.)
La signification de valuevarie selon l'itérateur; les tableaux prennent en charge (au moins) trois fonctions qui renvoient des itérateurs:
values(): C'est celui que j'ai utilisé ci-dessus. Elle retourne un itérateur où chacun valueest l'entrée de matrice pour cette itération ( "a", "b", et "c"dans l'exemple précédent).
keys(): Renvoie un itérateur où chacun valueest la clé de cette itération (donc pour notre aci-dessus, ce serait "0", alors "1", alors "2").
entries(): Renvoie un itérateur où chacun valueest un tableau dans le formulaire [key, value]pour cette itération.
Pour les objets de type tableau
Outre les vrais tableaux, il existe également des objets de type tableau qui ont une lengthpropriété et des propriétés avec des noms numériques: NodeListinstances, l' argumentsobjet, etc. Comment pouvons-nous parcourir leur contenu?
Utilisez l'une des options ci-dessus pour les tableaux
Au moins certaines, et peut-être la plupart ou même toutes, des approches de tableau ci-dessus s'appliquent fréquemment aussi bien aux objets de type tableau:
Utilisation forEachet connexes (ES5 +)
Les différentes fonctions de Array.prototypesont "intentionnellement génériques" et peuvent généralement être utilisées sur des objets de type tableau via Function#callou Function#apply. (Voir la mise en garde pour les objets fournis par l'hôte à la fin de cette réponse, mais c'est un problème rare.)
Array.prototype.forEach.call(node.childNodes,function(child){// Do something with `child`});
Si vous allez faire beaucoup de choses, vous voudrez peut-être récupérer une copie de la référence de fonction dans une variable pour la réutiliser, par exemple:
// (This is all presumably in some scoping function)var forEach =Array.prototype.forEach;// Then later...
forEach.call(node.childNodes,function(child){// Do something with `child`});
Utilisez une forboucle simple
De toute évidence, une simple forboucle s'applique aux objets de type tableau.
Utiliser for-incorrectement
for-inavec les mêmes garanties qu'avec un tableau devrait également fonctionner avec des objets de type tableau; la mise en garde pour les objets fournis par l'hôte sur # 1 ci-dessus peut s'appliquer.
Utiliser for-of(utiliser un itérateur implicitement) (ES2015 +)
for-ofutilise l' itérateur fourni par l'objet (le cas échéant). Cela inclut les objets fournis par l'hôte. Par exemple, la spécification de NodeListfrom a querySelectorAllété mise à jour pour prendre en charge l'itération. Les spécifications pour le HTMLCollectionde getElementsByTagNamen'était pas.
Utiliser explicitement un itérateur (ES2015 +)
Voir # 4.
Créer un vrai tableau
D'autres fois, vous souhaiterez peut-être convertir un objet de type tableau en un véritable tableau. Faire cela est étonnamment facile:
Utilisez la sliceméthode des tableaux
Nous pouvons utiliser la sliceméthode des tableaux, qui, comme les autres méthodes mentionnées ci-dessus, est "intentionnellement générique" et peut donc être utilisée avec des objets de type tableau, comme ceci:
var trueArray =Array.prototype.slice.call(arrayLikeObject);
Ainsi, par exemple, si nous voulons convertir un NodeListen un vrai tableau, nous pouvons le faire:
var divs =Array.prototype.slice.call(document.querySelectorAll("div"));
Voir la mise en garde pour les objets fournis par l'hôte ci- dessous. En particulier, notez que cela échouera dans IE8 et versions antérieures, ce qui ne vous permet pas d'utiliser des objets fournis par l'hôte thiscomme ça.
Utiliser la syntaxe étendue ( ...)
Il est également possible d'utiliser la syntaxe de propagation d'ES2015 avec des moteurs JavaScript qui prennent en charge cette fonctionnalité. Comme for-of, cela utilise l' itérateur fourni par l'objet (voir # 4 dans la section précédente):
var trueArray =[...iterableObject];
Ainsi, par exemple, si nous voulons convertir un NodeListen un vrai tableau, avec la syntaxe étendue, cela devient assez succinct:
var divs =[...document.querySelectorAll("div")];
Utilisation Array.from
Array.from(spec) | (MDN) (ES2015 +, mais facilement polyfilled) crée un tableau à partir d'un objet de type tableau, en passant éventuellement les entrées via une fonction de mappage en premier. Donc:
var divs =Array.from(document.querySelectorAll("div"));
Ou si vous vouliez obtenir un tableau des noms de balises des éléments avec une classe donnée, vous utiliseriez la fonction de mappage:
// Arrow function (ES2015):var divs =Array.from(document.querySelectorAll(".some-class"), element => element.tagName);// Standard function (since `Array.from` can be shimmed):var divs =Array.from(document.querySelectorAll(".some-class"),function(element){return element.tagName;});
Avertissement pour les objets fournis par l'hôte
Si tu utilises Array.prototype fonctions avec des objets de type tableau fournis par l' hôte (listes DOM et autres éléments fournis par le navigateur plutôt que le moteur JavaScript), vous devez vous assurer de tester dans vos environnements cibles pour vous assurer que l'objet fourni par l'hôte se comporte correctement. . La plupart se comportent correctement (maintenant), mais il est important de tester. La raison en est que la plupart des Array.prototypeméthodes que vous voudrez probablement utiliser reposent sur l'objet fourni par l'hôte qui donne une réponse honnête à l' [[HasProperty]]opération abstraite . Au moment d'écrire ces lignes, les navigateurs font un très bon travail, mais la spécification 5.1 permettait la possibilité qu'un objet fourni par l'hôte ne soit pas honnête. C'est au §8.6.2 , plusieurs paragraphes sous le grand tableau près du début de cette section), où il est écrit:
Les objets hôtes peuvent implémenter ces méthodes internes de quelque manière que ce soit, sauf indication contraire; par exemple, une possibilité est que [[Get]], [[Put]]pour un objet hôte particulier, il récupère et stocke les valeurs des propriétés, mais [[HasProperty]]génère toujours false .
(Je n'ai pas pu trouver le verbiage équivalent dans la spécification ES2015, mais c'est toujours le cas.) Encore une fois, à ce jour, les objets de type tableau fournis par l'hôte dans les navigateurs modernes [ NodeListinstances, par exemple] faire poignée [[HasProperty]]correctement, mais il est important de tester.)
Je voudrais également ajouter que .forEachcela ne peut pas être brisé efficacement. Vous devez lever une exception pour effectuer la pause.
Pijusn
82
@Pius: Si vous voulez rompre la boucle, vous pouvez utiliser some. (J'aurais préféré permettre la rupture forEachaussi, mais ils ne m'ont pas demandé. ;-))
TJ Crowder
6
@TJCrowder True, même si cela ressemble plus à une solution de contournement car ce n'est pas son objectif principal.
Pijusn
8
@ user889030: Vous avez besoin d'un ,après k=0, pas d'un ;. Rappelez-vous, la programmation est beaucoup de choses, dont une attention particulière aux détails ... :-)
TJ Crowder
5
@JimB: C'est couvert ci-dessus (et ce lengthn'est pas une méthode). :-)
TJ Crowder
513
Remarque : Cette réponse est désespérément obsolète. Pour une approche plus moderne, regardez les méthodes disponibles sur un tableau . Les méthodes d'intérêt peuvent être:
pour chaque
carte
filtre
Zip *: français
réduire
chaque
certains
La manière standard d'itérer un tableau en JavaScript est une forboucle vanille :
var length = arr.length,
element =null;for(var i =0; i < length; i++){
element = arr[i];// Do something with element}
Notez cependant que cette approche n'est bonne que si vous avez un tableau dense et que chaque index est occupé par un élément. Si le tableau est clairsemé, vous pouvez rencontrer des problèmes de performances avec cette approche, car vous itérerez sur un grand nombre d'indices qui n'existent pas vraiment dans le tableau. Dans ce cas, une for .. inboucle pourrait être une meilleure idée. Cependant , vous devez utiliser les protections appropriées pour vous assurer que seules les propriétés souhaitées du tableau (c'est-à-dire les éléments du tableau) sont prises en compte, car la for..inboucle -lo sera également énumérée dans les navigateurs hérités ou si les propriétés supplémentaires sont définies commeenumerable .
Dans ECMAScript 5, il y aura une méthode forEach sur le prototype de la baie, mais elle n'est pas prise en charge dans les navigateurs hérités. Donc, pour pouvoir l'utiliser de manière cohérente, vous devez soit avoir un environnement qui le prend en charge (par exemple, Node.js pour JavaScript côté serveur), soit utiliser un "Polyfill". Le Polyfill pour cette fonctionnalité est cependant trivial et comme il rend le code plus facile à lire, c'est un bon polyfill à inclure.
pourquoi n'est-ce for(instance in objArray) pas une utilisation correcte? cela me semble plus simple, mais j'entends que vous en parlez comme un moyen incorrect d'utilisation?
Dante1986
21
Vous pouvez utiliser la mise en cache de la longueur en ligne: pour (var i = 0, l = arr.length; i <l; i ++)
Robert Hoffmann
3
La virgule à la fin de la première ligne est-elle intentionnelle ou s'agit-il d'une faute de frappe (pourrait être un point-virgule)?
Mohd Abdul Mujib
6
@ wardha-Web C'est intentionnel. Il nous permet de déclarer plusieurs variables avec un seul varmot-clé. Si nous avions utilisé un point-virgule, alors elementil aurait été déclaré dans la portée globale (ou, plutôt, JSHint nous aurait crié dessus avant qu'il n'atteigne la production).
PatrikAkerstrand
239
Si vous utilisez la bibliothèque jQuery , vous pouvez utiliser jQuery.each :
$.each(yourArray,function(index, value){// do your stuff here});
ÉDITER :
Selon la question, l'utilisateur veut du code en javascript au lieu de jquery donc la modification est
var length = yourArray.length;for(var i =0; i < length; i++){// Do something with yourArray[i].}
Je vais probablement utiliser cette réponse le plus souvent. Ce n'est pas la meilleure réponse à la question, mais dans la pratique, ce sera la plus simple et la plus applicable pour ceux d'entre nous qui utilisent jQuery. Je pense que nous devrions tous apprendre la vanille aussi. Cela ne fait jamais de mal d'élargir votre compréhension.
mopsyd
47
Juste pour le plaisir: jQuery chacune est beaucoup plus lente que les solutions natives. Il est conseillé par jQuery d'utiliser JavaScript natif au lieu de jQuery chaque fois que cela est possible. jsperf.com/browser-diet-jquery-each-vs-for-loop
Kevin Boss
8
Abstenez-vous d'utiliser jQuery lorsque vous pouvez utiliser des vanille js
Noe
2
Tenez-vous au JS standard, gardez les bibliothèques tierces hors de la réponse à moins qu'il n'y ait pas de solution en langue native
scubasteve
116
Boucle en arrière
Je pense que l' inverse de la boucle mérite une mention ici:
for(var i = array.length; i--;){// process array[i]}
Avantages:
Vous n'avez pas besoin de déclarer une lenvariable temporaire ou de comparer avec array.lengthà chaque itération, l'une ou l'autre pouvant être une minute d'optimisation.
Supprimer les frères et sœurs du DOM dans l'ordre inverse est généralement plus efficace . (Le navigateur doit moins déplacer les éléments dans ses tableaux internes.)
Si vous modifiez le tableau pendant la boucle, à ou après l'index i (par exemple, vous supprimez ou insérez un élément à array[i]), alors une boucle directe ignorerait l'élément qui s'est déplacé vers la gauche en position i , ou retraiter le i ème élément qui était déplacé vers la droite. Dans une boucle for traditionnelle, vous pouvez mettre à jour i pour pointer vers l'élément suivant qui doit être traité - 1, mais simplement inverser le sens de l'itération est souvent une solution plus simple et plus élégante .
De même, lors de la modification ou de la suppression d' éléments DOM imbriqués , le traitement inverse peut éviter les erreurs . Par exemple, envisagez de modifier le innerHTML d'un nœud parent avant de gérer ses enfants. Au moment où le nœud enfant est atteint, il sera détaché du DOM, après avoir été remplacé par un enfant nouvellement créé lors de l'écriture du code HTML interne du parent.
Il est plus court à taper et à lire que certaines des autres options disponibles. Bien qu'il perd à forEach()et aux ES6 for ... of.
Désavantages:
Il traite les articles dans l'ordre inverse. Si vous construisiez un nouveau tableau à partir des résultats ou imprimiez des éléments à l'écran, la sortie sera naturellement inversée par rapport à l'ordre d'origine.
L'insertion répétée de frères et sœurs dans le DOM en tant que premier enfant afin de conserver leur ordre est moins efficace . (Le navigateur devrait continuer à déplacer les choses correctement.) Pour créer des nœuds DOM efficacement et dans l'ordre, il suffit de boucler vers l'avant et d'ajouter comme d'habitude (et d'utiliser également un "fragment de document").
La boucle inverse est source de confusion pour les développeurs juniors. (Vous pouvez considérer cela comme un avantage, selon vos perspectives.)
Dois-je toujours l'utiliser?
Certains développeurs utilisent l'inverse pour la boucle par défaut , sauf s'il existe une bonne raison de boucler vers l'avant.
Bien que les gains de performances soient généralement insignifiants, cela crie en quelque sorte:
"Faites juste ça pour chaque article de la liste, je me fiche de la commande!"
Cependant, dans la pratique, ce n'est pas réellement une indication fiable de l'intention, car il est impossible de les distinguer des occasions où vous vous souciez de la commande et avez vraiment besoin de boucler en sens inverse. Donc, en fait, une autre construction serait nécessaire pour exprimer avec précision l'intention de "ne pas s'en soucier", quelque chose actuellement indisponible dans la plupart des langues, y compris ECMAScript, mais qui pourrait être appelé, par exemple,forEachUnordered() ,.
Si l'ordre n'a pas d'importance et que l' efficacité est une préoccupation (dans la boucle la plus profonde d'un moteur de jeu ou d'animation), il peut être acceptable d'utiliser l'inverse pour la boucle comme modèle de référence. N'oubliez pas que voir une boucle inverse pour dans le code existant ne signifie pas nécessairement que l'ordre n'est pas pertinent!
Il valait mieux utiliser forEach ()
En général, pour le code de niveau supérieur où la clarté et la sécurité sont des préoccupations plus importantes, j'ai précédemment recommandé d'utiliser Array::forEachcomme modèle par défaut pour la boucle (bien que de nos jours je préfère utiliser for..of). Les raisons de préférer forEachune boucle inversée sont:
C'est plus clair à lire.
Cela indique que i ne va pas être décalé dans le bloc (ce qui est toujours une surprise possible se cachant dans les boucles longues foret while).
Il vous donne un champ libre pour les fermetures.
Il réduit la fuite de variables locales et les collisions accidentelles avec (et la mutation des) variables externes.
Ensuite, lorsque vous voyez l'inverse de la boucle dans votre code, c'est un indice qu'il est inversé pour une bonne raison (peut-être l'une des raisons décrites ci-dessus). Et le fait de voir une boucle avant traditionnelle peut indiquer que le décalage peut avoir lieu.
(Si la discussion de l'intention n'a aucun sens pour vous, alors vous et votre code pourriez bénéficier de regarder la conférence de Crockford sur le style de programmation et votre cerveau .)
Il est maintenant encore mieux d'utiliser for..of!
Il y a un débat pour savoir si for..ofou forEach()sont préférables:
Pour une prise en charge maximale du navigateur, for..ofnécessite un polyfill pour les itérateurs, ce qui rend votre application légèrement plus lente à exécuter et légèrement plus grande à télécharger.
Pour cette raison (et pour encourager l'utilisation de mapet filter), certains guides de style frontaux interdisent for..ofcomplètement!
Mais les préoccupations ci-dessus ne s'appliquent pas aux applications Node.js, où elles for..ofsont désormais bien prises en charge.
Personnellement, j'ai tendance à utiliser ce qui semble le plus facile à lire, sauf si les performances ou la minification sont devenues une préoccupation majeure. Donc, ces jours-ci, je préfère utiliser for..ofau lieu de forEach(), mais j'utiliserai toujours mapou filterou findou somelorsque cela s'applique. (Pour le bien de mes collègues, j'utilise rarement reduce.)
Comment ça marche?
for(var i =0; i < array.length; i++){...}// Forwardsfor(var i = array.length; i--;){...}// Reverse
Vous remarquerez que i--c'est la clause du milieu (où nous voyons généralement une comparaison) et la dernière clause est vide (où nous voyons généralement i++). Cela signifie que cela i--est également utilisé comme condition de poursuite. Fondamentalement, il est exécuté et vérifié avant chaque itération.
Parce qu'il i--s'exécute avant chaque itération, lors de la première itération, nous accèderons en fait à l'élément array.length - 1auquel vous éviterez tout problème avec les éléments hors limitesundefined .
Pourquoi ne cesse-t-il pas d'itérer avant l'index 0?
La boucle cesse d'itérer lorsque la condition est i--évaluée à une valeur de falsey (lorsqu'elle donne 0).
L'astuce est que, contrairement à --i, l' i--opérateur de fin décrémente imais donne la valeur avant la décrémentation. Votre console peut le démontrer:
> var i = 5; [i, i--, i];
[5, 5, 4]
Donc, la dernière itération, j'étais auparavant 1 et l' expression il passe à 0 , mais les rendements en fait 1 (truthy), et donc la condition passe. À l'itération suivante , i passe à -1 mais donne 0 (falsey), ce qui fait que l'exécution tombe immédiatement du bas de la boucle.i--i--
Dans les forwards traditionnels pour la boucle, i++et ++isont interchangeables (comme le souligne Douglas Crockford). Cependant, dans le sens inverse de la boucle, car notre décrément est également notre expression de condition, nous devons nous en tenir i--si nous voulons traiter l'élément à l'index 0.
Trivia
Certaines personnes aiment dessiner une petite flèche dans la forboucle inverse et terminer avec un clin d'œil:
for(var i = array.length; i -->0;){
Les crédits vont à WYL pour m'avoir montré les avantages et les horreurs du reverse for loop.
J'ai oublié d'ajouter les repères . J'ai également oublié de mentionner à quel point le bouclage inverse est une optimisation significative sur les processeurs 8 bits comme le 6502, où vous obtenez vraiment la comparaison gratuitement!
joeytwiddle
La même réponse est donnée de manière beaucoup plus concise ici (sur une question différente).
var index,
value;for(index in obj){
value = obj[index];}
Il y a un hic. for..inparcourra chacun des membres énumérables de l'objet et les membres de son prototype. Pour éviter de lire les valeurs héritées du prototype de l'objet, vérifiez simplement si la propriété appartient à l'objet:
for(i in obj){if(obj.hasOwnProperty(i)){//do stuff}}
De plus, ECMAScript 5 a ajouté une forEachméthode Array.prototypequi peut être utilisée pour énumérer un tableau à l'aide d'un calback (le polyfill est dans les documents afin que vous puissiez toujours l'utiliser pour les navigateurs plus anciens):
Il est important de noter que Array.prototype.forEachcela ne se casse pas lorsque le rappel revient false. jQuery et Underscore.js fournissent leurs propres variations eachpour fournir des boucles qui peuvent être court-circuitées.
Alors, comment peut-on sortir d'une boucle foreach ECMAScript5 comme nous le ferions pour une boucle for normale ou une boucle foreach comme celle trouvée dans les langages de style C?
Ciaran Gallagher
5
@CiaranG, en JavaScript, il est courant de voir des eachméthodes qui permettent return falsed'être utilisées pour sortir de la boucle, mais avec forEachce n'est pas une option. Un indicateur externe pourrait être utilisé (c'est-à if (flag) return;- dire , mais cela empêcherait uniquement le reste du corps de la fonction de s'exécuter, forEachcontinuerait à itérer sur toute la collection.
zzzzBov
43
Si vous souhaitez boucler sur un tableau, utilisez la forboucle en trois parties standard .
for(var i =0; i < myArray.length; i++){var arrayItem = myArray[i];}
Vous pouvez obtenir des optimisations de performances en mettant en cache myArray.lengthou en itérant en arrière.
pour (var i = 0, length = myArray.length; i <length; i ++) devrait le faire
Edson Medina
5
@EdsonMedina Cela créera également une nouvelle variable globale appelée length. ;)
joeytwiddle
4
@joeytwiddle Oui, mais cela dépasse le cadre de cet article. Vous allez quand même créer une variable globale i.
Edson Medina
6
@EdsonMedina Mes excuses, je me suis complètement trompé. L'utilisation ,après une affectation n'introduit pas de nouveau global, donc votre suggestion est très bien ! Je confondais cela pour un problème différent: l'utilisation =après une affectation crée un nouveau global.
joeytwiddle
Attention la variable i n'est pas locale à la boucle. JavaScript n'a pas de portée de bloc. Il est probablement préférable de déclarer var i, length, arrayItem;avant la boucle pour éviter ce malentendu.
James
35
Je sais que c'est un vieux post, et il y a déjà tellement de bonnes réponses. Pour un peu plus d'exhaustivité, j'ai pensé que j'en jetterais un autre en utilisant AngularJS . Bien sûr, cela ne s'applique que si vous utilisez Angular, évidemment, j'aimerais quand même le dire.
angular.forEachprend 2 arguments et un troisième argument facultatif. Le premier argument est l'objet (tableau) sur lequel itérer, le deuxième argument est la fonction itérateur, et le troisième argument facultatif est le contexte de l'objet (appelé fondamentalement à l'intérieur de la boucle «this»).
Il existe différentes façons d'utiliser la boucle forEach d'angular. Le plus simple et probablement le plus utilisé est
var temp =[1,2,3];
angular.forEach(temp,function(item){//item will be each element in the array//do something});
Une autre méthode utile pour copier des éléments d'un tableau vers un autre est
var temp =[1,2,3];var temp2 =[];
angular.forEach(temp,function(item){this.push(item);//"this" refers to the array passed into the optional third parameter so, in this case, temp2.}, temp2);
Bien que vous n'ayez pas à le faire, vous pouvez simplement faire ce qui suit et c'est équivalent à l'exemple précédent:
Il y a maintenant des avantages et des inconvénients à utiliser la angular.forEachfonction par opposition à la fonction intégrée à la vanillefor boucle .
Avantages
Lisibilité facile
Écriture facile
Si disponible, angular.forEachutilisera la boucle ES5 forEach. Maintenant, j'arriverai à l'efficacité dans la section contre, car les boucles forEach sont beaucoup plus lentes que les boucles for. Je le mentionne en tant que pro car c'est agréable d'être cohérent et standardisé.
Considérez les 2 boucles imbriquées suivantes, qui font exactement la même chose. Disons que nous avons 2 tableaux d'objets et que chaque objet contient un tableau de résultats, dont chacun a une propriété Value qui est une chaîne (ou autre). Et disons que nous devons répéter chacun des résultats et s'ils sont égaux, effectuez une action:
angular.forEach(obj1.results,function(result1){
angular.forEach(obj2.results,function(result2){if(result1.Value=== result2.Value){//do something}});});//exact same with a for loopfor(var i =0; i < obj1.results.length; i++){for(var j =0; j < obj2.results.length; j++){if(obj1.results[i].Value=== obj2.results[j].Value){//do something}}}
Certes, c'est un exemple hypothétique très simple, mais j'ai écrit triple intégré pour les boucles en utilisant la deuxième approche et il était très difficile à lire et à écrire d'ailleurs.
Les inconvénients
Efficacité. angular.forEach, et le natif forEach, d'ailleurs, sont tous deux beaucoup plus lents que la forboucle normale ... environ 90% plus lents . Donc, pour les grands ensembles de données, mieux vaut s'en tenir à la forboucle native .
Aucune interruption, poursuite ou retour d'assistance. continueest en fait pris en charge par " accident ", pour continuer dans un angular.forEachsimple, mettez une return;instruction dans la fonction comme angular.forEach(array, function(item) { if (someConditionIsTrue) return; });ce qui la fera sortir de la fonction pour cette itération. Cela est également dû au fait que le natif forEachne prend pas en charge la pause ou la poursuite non plus.
Je suis sûr qu'il existe également d'autres avantages et inconvénients, et n'hésitez pas à ajouter ceux que vous jugez appropriés. Je pense que, en fin de compte, si vous avez besoin d'efficacité, restez avec la forboucle native pour vos besoins de boucle. Mais, si vos jeux de données sont plus petits et qu'une certaine efficacité est acceptable pour abandonner en échange de la lisibilité et de l'écriture, alors par tous les moyens, jetez un angular.forEachmauvais garçon.
var x;while(x = y.pop()){
alert(x);//do something }
xcontiendra la dernière valeur de yet sera supprimée du tableau. Vous pouvez également utiliser shift()ce qui donnera et supprimera le premier élément de y.
function forEach(list,callback){var length = list.length;for(var n =0; n < length; n++){
callback.call(list[n]);}}var myArray =['hello','world'];
forEach(
myArray,function(){
alert(this);// do something});
La for(i = 0; i < array.length; i++)boucle n'est probablement pas le meilleur choix. Pourquoi? Si vous avez ceci:
var array =newArray();
array[1]="Hello";
array[7]="World";
array[11]="!";
La méthode appellera de array[0]à array[2]. Premièrement, cela référencera d'abord les variables que vous n'avez même pas, deuxièmement vous n'aurez pas les variables dans le tableau, et troisièmement cela rendra le code plus audacieux. Regardez ici, c'est ce que j'utilise:
for(var i in array){var el = array[i];//If you want 'i' to be INT just put parseInt(i)//Do something with el}
Et si vous voulez que ce soit une fonction, vous pouvez le faire:
function foreach(array, call){for(var i in array){
call(array[i]);}}
Si vous voulez casser, un peu plus de logique:
function foreach(array, call){for(var i in array){if(call(array[i])==false){break;}}}
Il existe trois implémentations de foreachdans jQuery comme suit.
var a =[3,2];
$(a).each(function(){console.log(this.valueOf())});//Method 1
$.each(a,function(){console.log(this.valueOf())});//Method 2
$.each($(a),function(){console.log(this.valueOf())});//Method 3
Où ofévite les bizarreries associées inet le fait fonctionner comme la forboucle de toute autre langue, et letliei à l'intérieur de la boucle plutôt qu'à l'intérieur de la fonction.
Les accolades ( {}) peuvent être omises lorsqu'il n'y a qu'une seule commande (par exemple dans l'exemple ci-dessus).
Une solution simple serait maintenant d'utiliser la bibliothèque underscore.js . Il fournit de nombreux outils utiles, tels que eachet déléguera automatiquement le travail au natif forEachsi disponible.
Il n'y a pas de for eachboucle en JavaScript natif . Vous pouvez soit utiliser des bibliothèques pour obtenir cette fonctionnalité (je recommande Underscore.js ), utiliser une forboucle simple .
Il s'agit d'un itérateur pour la liste NON clairsemée où l'index commence à 0, ce qui est le scénario typique lors du traitement de document.getElementsByTagName ou document.querySelectorAll)
function each( fn, data ){if(typeof fn =='string')eval('fn = function(data, i){'+ fn +'}');for(var i=0, L=this.length; i < L; i++)
fn.call(this[i], data, i );returnthis;}Array.prototype.each = each;
Exemples d'utilisation:
Exemple 1
var arr =[];[1,2,3].each(function(a){ a.push(this*this}, arr);
arr =[1,4,9]
each.call(document.getElementsByTagName('p'),"if( i % 2 == 0) this.className = data;",'red');
Chaque autre balise p obtient class="red">
Exemple # 4
each.call(document.querySelectorAll('p.blue'),function(newClass, i){if( i <20)this.className = newClass;},'green');
Et enfin, les 20 premières balises p bleues sont passées au vert
Attention lorsque vous utilisez une chaîne comme fonction: la fonction est créée hors contexte et ne doit être utilisée que lorsque vous êtes certain de la portée des variables. Sinon, mieux vaut passer des fonctions où la portée est plus intuitive.
Il existe plusieurs façons de parcourir un tableau en JavaScript, comme ci-dessous:
car - c'est le plus courant . Bloc complet de code pour le bouclage
var languages =["Java","JavaScript","C#","Python"];var i, len, text;for(i =0, len = languages.length, text =""; i < len; i++){
text += languages[i]+"<br>";}
document.getElementById("example").innerHTML = text;
Boucles fonctionnelles - forEach, map, filteraussi reduce(ils boucle par la fonction, mais ils sont utilisés si vous avez besoin de faire quelque chose avec votre tableau, etc.
// For example, in this case we loop through the number and double them up using the map functionvar numbers =[65,44,12,4];
document.getElementById("example").innerHTML = numbers.map(function(num){return num *2});
Petite correction: forEachn'est pas une boucle "fonctionnelle" car elle ne retourne pas de nouvelle Array(en fait elle ne retourne rien), elle ne fait qu'itérer.
nicholaswmin
19
ECMAScript 5 (la version sur JavaScript) pour travailler avec les tableaux:
forEach - Parcourt chaque élément du tableau et fait tout ce dont vous avez besoin avec chaque élément.
['C','D','E'].forEach(function(element, index){
console.log(element +" is #"+(index+1)+" in the musical scale");});// Output// C is the #1 in musical scale// D is the #2 in musical scale// E is the #3 in musical scale
Dans le cas, plus intéressé par le fonctionnement sur la baie en utilisant une fonctionnalité intégrée.
map - Il crée un nouveau tableau avec le résultat de la fonction de rappel. Cette méthode peut être utilisée lorsque vous devez formater les éléments de votre tableau.
// Let's upper case the items in the array['bob','joe','jen'].map(function(elem){return elem.toUpperCase();});// Output: ['BOB', 'JOE', 'JEN']
réduire - Comme son nom l'indique, il réduit le tableau à une seule valeur en appelant la fonction donnée en passant dans l'élément en cours et le résultat de l'exécution précédente.
Il n'y a aucune capacité intrinsèque à s'introduire forEach. Pour interrompre l'exécution, utilisez ce qui Array#somesuit:
[1,2,3].some(function(number){return number ===1;});
Cela fonctionne car somerenvoie true dès que l'un des rappels, exécuté dans l'ordre du tableau, retourne true, court-circuitant l'exécution du reste.
Réponse originale,
voir prototype Array pour certains
Je voudrais également ajouter cela comme une composition d'une boucle inverse et une réponse ci-dessus pour quelqu'un qui aimerait cette syntaxe aussi.
var foo =[object,object,object];for(var i = foo.length, item; item = foo[--i];){
console.log(item);}
Avantages:
L'avantage pour cela: vous avez déjà la référence dans la première comme celle-ci qui n'aura pas besoin d'être déclarée plus tard avec une autre ligne. C'est pratique lors de la boucle à travers le tableau d'objets.
Les inconvénients:
Cela se cassera chaque fois que la référence est fausse - falsey (non défini, etc.). Il peut cependant être utilisé comme un avantage. Cependant, cela rendrait la lecture un peu plus difficile. De plus, selon le navigateur, il peut être "non" optimisé pour fonctionner plus rapidement que celui d'origine.
La déstructuration et l'utilisation de l'opérateur de diffusion se sont révélées très utiles pour les nouveaux arrivants à ECMAScript 6 car elles sont plus lisibles / esthétiques, bien que certains vétérans de JavaScript puissent le considérer comme désordonné. Les juniors ou d'autres personnes pourraient trouver cela utile.
Les exemples suivants utiliseront l' for...ofinstruction et la .forEachméthode.
Exemples 6, 7 et 8 peuvent être utilisés avec toutes les boucles fonctionnelles comme .map, .filter, .reduce, .sort, .every, .some. Pour plus d'informations sur ces méthodes, consultez l' objet tableau .
Exemple 1:for...of boucle normale - pas d'astuces ici.
let arrSimple =['a','b','c'];for(let letter of arrSimple){
console.log(letter);}
let arrFruits =['apple','orange','banana'];for(let[firstLetter,...restOfTheWord]of arrFruits){// Create a shallow copy using the spread operatorlet[lastLetter]=[...restOfTheWord].reverse();
console.log(firstLetter, lastLetter, restOfTheWord);}
// let arrSimple = ['a', 'b', 'c'];// Instead of keeping an index in `i` as per example `for(let i = 0 ; i<arrSimple.length;i++)`// this example will use a multi-dimensional array of the following format type:// `arrWithIndex: [number, string][]`let arrWithIndex =[[0,'a'],[1,'b'],[2,'c'],];// Same thing can be achieved using `.map` method// let arrWithIndex = arrSimple.map((i, idx) => [idx, i]);// Same thing can be achieved using `Object.entries`// NOTE: `Object.entries` method doesn't work on Internet Explorer unless it's polyfilled// let arrWithIndex = Object.entries(arrSimple);for(let[key, value]of arrWithIndex){
console.log(key, value);}
let arrWithIndex =[[0,'a'],[1,'b'],[2,'c'],];// Not to be confused here, `forEachIndex` is the real index// `mappedIndex` was created by "another user", so you can't really trust it
arrWithIndex.forEach(([mappedIndex, item], forEachIndex)=>{
console.log(forEachIndex, mappedIndex, item);});
let arrWithObjects =[{
name:'Jon',
age:32},{
name:'Elise',
age:33}];// NOTE: Destructuring objects while using shorthand functions// are required to be surrounded by parentheses
arrWithObjects.forEach(({ name, age: aliasForAge })=>{
console.log(name, aliasForAge)});
Un moyen le plus proche de votre idée serait d'utiliser Array.forEach()qui accepte une fonction de fermeture qui sera exécutée pour chaque élément du tableau.
myArray.forEach((item)=>{// Do something
console.log(item);});
Une autre façon viable serait d'utiliser Array.map()ce qui fonctionne de la même manière, mais il prend également toutes les valeurs que vous renvoyez et les renvoie dans un nouveau tableau (mappant essentiellement chaque élément à un nouveau), comme ceci:
C'est faux, mapcela ne mute pas les éléments du tableau, car il renvoie un nouveau tableau, les éléments de ce nouveau étant le résultat de l'application de la fonction aux éléments de l'ancien tableau.
Jesús Franco
Je n'ai jamais dit qu'il ne renvoyait pas un nouveau tableau, je faisais référence au changement appliqué par la fonction. Mais ici, je vais le changer dans la réponse.
Ante Jablan Adamović
encore une fois faux, la carte ne modifie pas ou ne mute pas du tout les éléments du tableau d'origine, j'ai proposé et édité la réponse en soulignant que la carte fonctionne avec une copie des éléments d'origine, laissant le tableau d'origine intact du tout
Jesús Franco
7
Vous pouvez appeler chacun comme ceci:
forEachitérera sur le tableau que vous fournissez et pour chaque itération qu'il aura, elementqui contient la valeur de cette itération. Si vous avez besoin d'un index, vous pouvez obtenir l'index actuel en passanti le second paramètre dans la fonction de rappel de forEach.
Foreach est fondamentalement une fonction d'ordre élevé, qui prend une autre fonction comme paramètre.
let theArray=[1,3,2];
theArray.forEach((element)=>{// Use the element of the array
console.log(element)}
Production:
132
Vous pouvez également parcourir un tableau comme celui-ci:
for(let i=0; i<theArray.length; i++){
console.log(i);// i will have the value of each index}
Si vous souhaitez parcourir un tableau d'objets avec la fonction flèche:
let arr =[{name:'john', age:50},{name:'clark', age:19},{name:'mohan', age:26}];
arr.forEach((person)=>{
console.log('I am '+ person.name +' and I am '+ person.age +' old');})
La syntaxe lambda ne fonctionne généralement pas dans Internet Explorer 10 ou inférieur.
J'utilise habituellement le
[].forEach.call(arrayName,function(value,index){
console.log("value of the looped element"+ value);
console.log("index of the looped element"+ index);});
Si vous êtes un fan de jQuery et que vous avez déjà un fichier jQuery en cours d'exécution, vous devez inverser les positions des paramètres d'index et de valeur
$("#ul>li").each(function(**index, value**){
console.log("value of the looped element"+ value);
console.log("index of the looped element"+ index);});
Si vous disposez d'un réseau massif, vous devez l'utiliser iteratorspour gagner en efficacité. Itérateurs sont une propriété de certaines collections de JavaScript (comme Map, Set, String, Array). Même, for..ofutilise iteratorsous le capot.
Les itérateurs améliorent l'efficacité en vous permettant de consommer les éléments d'une liste un par un comme s'ils étaient un flux. Ce qui rend un itérateur spécial, c'est comment il parcourt une collection. D'autres boucles doivent charger la collection entière à l'avance afin d'itérer dessus, alors qu'un itérateur n'a besoin que de connaître la position actuelle dans la collection.
Vous accédez à l'élément en cours en appelant la nextméthode de l'itérateur . La méthode suivante renverra le valuede l'élément actuel et un booleanpour indiquer quand vous avez atteint la fin de la collection. Voici un exemple de création d'un itérateur à partir d'un tableau.
Transformez votre tableau régulier en itérateur en utilisant une values()méthode comme celle-ci:
const myArr =[2,3,4]let it = myArr.values();
console.log(it.next());
console.log(it.next());
console.log(it.next());
console.log(it.next());
Conformément à la nouvelle fonctionnalité mise à jour ECMAScript 6 (ES6) et ECMAScript 2015, vous pouvez utiliser les options suivantes avec des boucles:
pour boucles
for(var i =0; i <5; i++){
console.log(i);}// Output: 0,1,2,3,4
pour ... en boucles
let obj ={"a":1,"b":2}for(let k in obj){
console.log(k)}// Output: a,b
Array.forEach ()
let array =[1,2,3,4]
array.forEach((x)=>{
console.log(x);})// Output: 1,2,3,4
pour ... des boucles
let array =[1,2,3,4]for(let x of array){
console.log(x);}// Output: 1,2,3,4
tandis que les boucles
let x =0while(x <5){
console.log(x)
x++}// Output: 1,2,3,4
faire ... tandis que les boucles
let x =0do{
console.log(x)
x++}while(x <5)// Output: 1,2,3,4
Aujourd'hui (18/12/2019), j'effectue un test sur mon macOS v10.13.6 (High Sierra), sur Chrome v 79.0, Safari v13.0.4 et Firefox v71.0 (64 bits) - conclusions sur l'optimisation (et la micro-optimisation qui il n'est généralement pas utile de l'introduire dans le code car l'avantage est faible, mais la complexité du code augmente).
Il semble que le traditionnel for i( Aa ) soit un bon choix pour écrire du code rapide sur tous les navigateurs.
Les autres solutions, comme for-of( Ad ), toutes dans le groupe C. ... sont généralement 2 à 10 (et plus) plus lentes que Aa , mais pour les petits tableaux, il est correct de les utiliser - pour augmenter la clarté du code.
Les boucles de longueur de tableau mises en cache dans n( Ab, Bb, Be ) sont parfois plus rapides, parfois non. Les compilateurs détectent probablement cette situation et introduisent la mise en cache. Les différences de vitesse entre les versions en cache et sans cache ( Aa, Ba, Bd ) sont d'environ ~ 1%, il semble donc que l'introduction nsoit une micro-optimisation .
Les i--solutions similaires où la boucle commence à partir du dernier élément du tableau ( Ac, Bc ) sont généralement ~ 30% plus lentes que les solutions directes - probablement la raison est le mode de fonctionnement du cache de la mémoire CPU - la lecture de la mémoire directe est plus optimale pour la mise en cache CPU). Il est recommandé de NE PAS UTILISER de telles solutions.
Détails
Dans les tests, nous calculons la somme des éléments du tableau. J'effectue un test pour les petits tableaux (10 éléments) et les grands tableaux (1 M éléments) et les divise en trois groupes:
Lors de l'itération sur un tableau, nous souhaitons souvent atteindre l'un des objectifs suivants:
Nous voulons parcourir le tableau et créer un nouveau tableau:
Array.prototype.map
Nous voulons parcourir le tableau et ne pas créer de nouveau tableau:
Array.prototype.forEach
for..ofboucle
En JavaScript, il existe de nombreuses façons d'atteindre ces deux objectifs. Cependant, certains sont plus pratiques que d'autres. Vous trouverez ci-dessous quelques méthodes couramment utilisées (l'IMO la plus pratique) pour effectuer l'itération de tableau en JavaScript.
Création d'un nouveau tableau: Map
map()est une fonction située sur Array.prototypelaquelle peut transformer chaque élément d'un tableau, puis retourne un nouveau tableau. map()prend comme argument une fonction de rappel et fonctionne de la manière suivante:
let arr =[1,2,3,4,5];let newArr = arr.map((element, index, array)=>{return element *2;})
console.log(arr);
console.log(newArr);
Le rappel dans lequel nous sommes passés map()comme argument est exécuté pour chaque élément. Ensuite, un tableau est renvoyé qui a la même longueur que le tableau d'origine. Dans ce nouvel élément de tableau est transformé par la fonction de rappel passée en argument à map().
La différence distincte entre mapet un autre mécanisme de boucle comme forEachet une for..ofboucle est que maprenvoie un nouveau tableau et laisse l'ancien tableau intact (sauf si vous le manipulez explicitement avec pense commesplice ).
Notez également que le maprappel de la fonction fournit le numéro d'index de l'itération en cours comme deuxième argument. De plus, le troisième argument fournit-il le tableau sur lequel a mapété appelé? Parfois, ces propriétés peuvent être très utiles.
Boucle utilisant forEach
forEachest une fonction qui se trouve sur Array.prototypelaquelle prend une fonction de rappel comme argument. Il exécute ensuite cette fonction de rappel pour chaque élément du tableau. Contrairement à la map()fonction, la fonction forEach ne renvoie rien ( undefined). Par exemple:
let arr =[1,2,3,4,5];
arr.forEach((element, index, array)=>{
console.log(element *2);if(index ===4){
console.log(array)}// index, and oldArray are provided as 2nd and 3th argument by the callback})
console.log(arr);
Tout comme la mapfonction, le forEachrappel fournit le numéro d'index de l'itération en cours comme deuxième argument. De plus, le troisième argument fournit-il le tableau sur lequel a forEachété appelé?
Parcourez les éléments en utilisant for..of
La for..ofboucle parcourt chaque élément d'un tableau (ou tout autre objet itérable). Cela fonctionne de la manière suivante:
let arr =[1,2,3,4,5];for(let element of arr){
console.log(element *2);}
Dans l'exemple ci-dessus, elementreprésente un élément de tableau et arrest le tableau que nous voulons boucler. Notez que le nom elementest arbitraire, et nous aurions pu choisir n'importe quel autre nom comme 'el' ou quelque chose de plus déclaratif lorsque cela est applicable.
Ne confondez pas la for..inboucle avec la for..ofboucle. for..inparcourra toutes les propriétés énumérables du tableau tandis que la for..ofboucle ne parcourra que les éléments du tableau. Par exemple:
let arr =[1,2,3,4,5];
arr.foo ='foo';for(let element of arr){
console.log(element);}for(let element in arr){
console.log(element);}
forEach
et pas seulementfor
. comme indiqué, en c # c'était un peu différent, et ça m'a dérouté :)i < len
et celai++
peut être fait par le moteur, plutôt que par l'interprète.)Réponses:
TL; DR
for-in
sauf si vous l'utilisez avec des garanties ou si vous savez au moins pourquoi il pourrait vous mordre.Vos meilleurs paris sont généralement
for-of
boucle (ES2015 + uniquement),Array#forEach
(spec
|MDN
) (ou ses prochessome
et autres) (ES5 + uniquement),for
boucle à l' ancienne ,for-in
avec des garanties.Mais il y a beaucoup plus à explorer, à lire ...
JavaScript a une sémantique puissante pour parcourir les tableaux et les objets de type tableau. J'ai divisé la réponse en deux parties: les options pour les tableaux authentiques et les options pour les choses qui sont juste comme des tableaux , comme l'
arguments
objet, d'autres objets itérables (ES2015 +), les collections DOM, etc.Je noterai rapidement que vous pouvez utiliser les options ES2015 maintenant , même sur les moteurs ES5, en transposant ES2015 en ES5. Recherchez "ES2015 transpiling" / "ES6 transpiling" pour en savoir plus ...
D'accord, regardons nos options:
Pour les tableaux réels
Vous avez trois options dans ECMAScript 5 ("ES5"), la version la plus largement prise en charge pour le moment, et deux autres ajoutées dans ECMAScript 2015 ("ES2015", "ES6"):
forEach
et connexes (ES5 +)for
boucle simplefor-in
correctementfor-of
(utiliser un itérateur implicitement) (ES2015 +)Détails:
1. Utilisation
forEach
et connexesDans tout environnement vaguement moderne (donc pas IE8) où vous avez accès aux
Array
fonctionnalités ajoutées par ES5 (directement ou à l'aide de polyfills), vous pouvez utiliserforEach
(spec
|MDN
):forEach
accepte une fonction de rappel et, éventuellement, une valeur à utiliser commethis
lors de l'appel de ce rappel (non utilisé ci-dessus). Le rappel est appelé pour chaque entrée du tableau, dans l'ordre, en ignorant les entrées inexistantes dans les tableaux clairsemés. Bien que j'aie utilisé un seul argument ci-dessus, le rappel est appelé avec trois: la valeur de chaque entrée, l'index de cette entrée et une référence au tableau que vous parcourez (au cas où votre fonction ne l'aurait pas déjà à portée de main) ).À moins que vous ne preniez en charge des navigateurs obsolètes comme IE8 (que NetApps affiche avec un peu plus de 4% de part de marché au moment de la rédaction de cet article en septembre 2016), vous pouvez utiliser avec plaisir
forEach
une page Web à usage général sans cale. Si vous devez prendre en charge des navigateurs obsolètes, le calage / polyfillingforEach
se fait facilement (recherchez "shim es5" pour plusieurs options).forEach
a l'avantage que vous n'avez pas à déclarer les variables d'indexation et de valeur dans la portée contenante, car elles sont fournies en tant qu'arguments à la fonction d'itération, et si bien étendues à cette itération.Si vous vous inquiétez du coût d'exécution d'un appel de fonction pour chaque entrée de tableau, ne le soyez pas; détails .
De plus,
forEach
est la fonction "boucle à travers tous", mais ES5 a défini plusieurs autres fonctions utiles "travaillez à travers le tableau et faites des choses", y compris:every
(arrête de boucler la première fois que le rappel revientfalse
ou quelque chose de faux)some
(arrête de boucler la première fois que le rappel revienttrue
ou quelque chose de vrai)filter
(crée un nouveau tableau comprenant des éléments où la fonction de filtre revienttrue
et en omettant ceux où elle revientfalse
)map
(crée un nouveau tableau à partir des valeurs renvoyées par le rappel)reduce
(construit une valeur en appelant à plusieurs reprises le rappel, en passant les valeurs précédentes; voir la spécification pour les détails; utile pour additionner le contenu d'un tableau et bien d'autres choses)reduceRight
(commereduce
, mais fonctionne dans l'ordre décroissant plutôt que croissant)2. Utilisez une
for
boucle simpleParfois, les anciennes méthodes sont les meilleures:
Si la longueur du tableau ne change pas pendant la boucle, et qu'il est en code sensible aux performances (peu probable), une version légèrement plus compliquée saisissant la longueur à l'avant pourrait être un tout petit peu plus rapide:
Et / ou en comptant à rebours:
Mais avec les moteurs JavaScript modernes, il est rare que vous ayez besoin de retirer ce dernier morceau de jus.
Dans ES2015 et supérieur, vous pouvez rendre vos variables d'index et de valeur locales à la
for
boucle:Afficher l'extrait de code
Et lorsque vous faites cela, non seulement
value
mais aussiindex
est recréé pour chaque itération de boucle, ce qui signifie que les fermetures créées dans le corps de la boucle gardent une référence auindex
(etvalue
) créé pour cette itération spécifique:Afficher l'extrait de code
Si vous aviez cinq divisions, vous obtiendrez "Index is: 0" si vous avez cliqué sur le premier et "Index is: 4" si vous avez cliqué sur le dernier. Cela ne fonctionne pas si vous utilisez
var
au lieu delet
.3. Utilisez
for-in
correctementVous aurez des gens qui vous disent d'utiliser
for-in
, mais ce n'est pas ce quifor-in
est pour .for-in
parcourt les propriétés énumérables d'un objet , pas les index d'un tableau. La commande n'est pas garantie , pas même en ES2015 (ES6). ES2015 + ne définit un ordre de propriétés de l' objet (via[[OwnPropertyKeys]]
,[[Enumerate]]
et les choses qui les utilisent commeObject.getOwnPropertyKeys
), mais il n'a pas précisé quefor-in
suivraient cet ordre; Mais ES2020 l'a fait. (Détails dans cette autre réponse .)Les seuls cas d'utilisation réels pour
for-in
un tableau sont:En ne regardant que ce premier exemple: vous pouvez utiliser
for-in
pour visiter ces éléments de tableau clairsemés si vous utilisez des protections appropriées:Notez les trois contrôles:
Que l'objet a sa propre propriété de ce nom (pas celle qu'il hérite de son prototype), et
Que la clé est composée de chiffres décimaux (par exemple, une chaîne de caractères normale et non une notation scientifique), et
Que la valeur de la clé lorsqu'elle est contrainte à un nombre est <= 2 ^ 32 - 2 (qui est 4 294 967 294). D'où vient ce chiffre? Cela fait partie de la définition d'un index de tableau dans la spécification . Les autres nombres (non entiers, nombres négatifs, nombres supérieurs à 2 ^ 32 - 2) ne sont pas des index de tableau. La raison pour laquelle c'est 2 ^ 32 - 2 est que cela fait que la plus grande valeur d'index est inférieure à 2 ^ 32 - 1 , qui est la valeur maximale qu'un tableau
length
peut avoir. (Par exemple, la longueur d'un tableau tient dans un entier non signé 32 bits.) (Props à RobG pour avoir souligné dans un commentaire sur mon blog que mon test précédent n'était pas tout à fait correct.)Vous ne feriez pas cela en code intégré, bien sûr. Vous écririez une fonction utilitaire. Peut-être:
Afficher l'extrait de code
4. Utilisation
for-of
(utilisez un itérateur implicitement) (ES2015 +)ES2015 a ajouté des itérateurs à JavaScript. La nouvelle façon d'utiliser les itérateurs est la nouvelle
for-of
instruction. Cela ressemble à ceci:Sous les couvertures, qui obtient un itérateur du tableau et boucle à travers lui, obtenant les valeurs de celui-ci. Cela n'a pas le problème que l'utilisation
for-in
a, car il utilise un itérateur défini par l'objet (le tableau), et les tableaux définissent que leurs itérateurs parcourent leurs entrées (et non leurs propriétés). Contrairementfor-in
à ES5, l'ordre dans lequel les entrées sont visitées est l'ordre numérique de leurs index.5. Utilisez explicitement un itérateur (ES2015 +)
Parfois, vous souhaiterez peut-être utiliser explicitement un itérateur . Vous pouvez aussi le faire, même si c'est beaucoup plus maladroit que . Cela ressemble à ceci:
for-of
L'itérateur est un objet correspondant à la définition de l'itérateur dans la spécification. Sa
next
méthode retourne un nouvel objet résultat chaque fois que vous l'appelez. L'objet résultat a une propriété,done
nous indiquant si c'est fait, et une propriétévalue
avec la valeur de cette itération. (done
est facultatif s'il le seraitfalse
,value
est facultatif s'il le seraitundefined
.)La signification de
value
varie selon l'itérateur; les tableaux prennent en charge (au moins) trois fonctions qui renvoient des itérateurs:values()
: C'est celui que j'ai utilisé ci-dessus. Elle retourne un itérateur où chacunvalue
est l'entrée de matrice pour cette itération ("a"
,"b"
, et"c"
dans l'exemple précédent).keys()
: Renvoie un itérateur où chacunvalue
est la clé de cette itération (donc pour notrea
ci-dessus, ce serait"0"
, alors"1"
, alors"2"
).entries()
: Renvoie un itérateur où chacunvalue
est un tableau dans le formulaire[key, value]
pour cette itération.Pour les objets de type tableau
Outre les vrais tableaux, il existe également des objets de type tableau qui ont une
length
propriété et des propriétés avec des noms numériques:NodeList
instances, l'arguments
objet, etc. Comment pouvons-nous parcourir leur contenu?Utilisez l'une des options ci-dessus pour les tableaux
Au moins certaines, et peut-être la plupart ou même toutes, des approches de tableau ci-dessus s'appliquent fréquemment aussi bien aux objets de type tableau:
Utilisation
forEach
et connexes (ES5 +)Les différentes fonctions de
Array.prototype
sont "intentionnellement génériques" et peuvent généralement être utilisées sur des objets de type tableau viaFunction#call
ouFunction#apply
. (Voir la mise en garde pour les objets fournis par l'hôte à la fin de cette réponse, mais c'est un problème rare.)Supposons que vous vouliez utiliser
forEach
surNode
des »childNodes
biens. Vous feriez ceci:Si vous allez faire beaucoup de choses, vous voudrez peut-être récupérer une copie de la référence de fonction dans une variable pour la réutiliser, par exemple:
Utilisez une
for
boucle simpleDe toute évidence, une simple
for
boucle s'applique aux objets de type tableau.Utiliser
for-in
correctementfor-in
avec les mêmes garanties qu'avec un tableau devrait également fonctionner avec des objets de type tableau; la mise en garde pour les objets fournis par l'hôte sur # 1 ci-dessus peut s'appliquer.Utiliser
for-of
(utiliser un itérateur implicitement) (ES2015 +)for-of
utilise l' itérateur fourni par l'objet (le cas échéant). Cela inclut les objets fournis par l'hôte. Par exemple, la spécification deNodeList
from aquerySelectorAll
été mise à jour pour prendre en charge l'itération. Les spécifications pour leHTMLCollection
degetElementsByTagName
n'était pas.Utiliser explicitement un itérateur (ES2015 +)
Voir # 4.
Créer un vrai tableau
D'autres fois, vous souhaiterez peut-être convertir un objet de type tableau en un véritable tableau. Faire cela est étonnamment facile:
Utilisez la
slice
méthode des tableauxNous pouvons utiliser la
slice
méthode des tableaux, qui, comme les autres méthodes mentionnées ci-dessus, est "intentionnellement générique" et peut donc être utilisée avec des objets de type tableau, comme ceci:Ainsi, par exemple, si nous voulons convertir un
NodeList
en un vrai tableau, nous pouvons le faire:Voir la mise en garde pour les objets fournis par l'hôte ci- dessous. En particulier, notez que cela échouera dans IE8 et versions antérieures, ce qui ne vous permet pas d'utiliser des objets fournis par l'hôte
this
comme ça.Utiliser la syntaxe étendue (
...
)Il est également possible d'utiliser la syntaxe de propagation d'ES2015 avec des moteurs JavaScript qui prennent en charge cette fonctionnalité. Comme
for-of
, cela utilise l' itérateur fourni par l'objet (voir # 4 dans la section précédente):Ainsi, par exemple, si nous voulons convertir un
NodeList
en un vrai tableau, avec la syntaxe étendue, cela devient assez succinct:Utilisation
Array.from
Array.from
(spec) | (MDN) (ES2015 +, mais facilement polyfilled) crée un tableau à partir d'un objet de type tableau, en passant éventuellement les entrées via une fonction de mappage en premier. Donc:Ou si vous vouliez obtenir un tableau des noms de balises des éléments avec une classe donnée, vous utiliseriez la fonction de mappage:
Avertissement pour les objets fournis par l'hôte
Si tu utilises
Array.prototype
fonctions avec des objets de type tableau fournis par l' hôte (listes DOM et autres éléments fournis par le navigateur plutôt que le moteur JavaScript), vous devez vous assurer de tester dans vos environnements cibles pour vous assurer que l'objet fourni par l'hôte se comporte correctement. . La plupart se comportent correctement (maintenant), mais il est important de tester. La raison en est que la plupart desArray.prototype
méthodes que vous voudrez probablement utiliser reposent sur l'objet fourni par l'hôte qui donne une réponse honnête à l'[[HasProperty]]
opération abstraite . Au moment d'écrire ces lignes, les navigateurs font un très bon travail, mais la spécification 5.1 permettait la possibilité qu'un objet fourni par l'hôte ne soit pas honnête. C'est au §8.6.2 , plusieurs paragraphes sous le grand tableau près du début de cette section), où il est écrit:(Je n'ai pas pu trouver le verbiage équivalent dans la spécification ES2015, mais c'est toujours le cas.) Encore une fois, à ce jour, les objets de type tableau fournis par l'hôte dans les navigateurs modernes [
NodeList
instances, par exemple] faire poignée[[HasProperty]]
correctement, mais il est important de tester.)la source
.forEach
cela ne peut pas être brisé efficacement. Vous devez lever une exception pour effectuer la pause.some
. (J'aurais préféré permettre la ruptureforEach
aussi, mais ils ne m'ont pas demandé. ;-)),
aprèsk=0
, pas d'un;
. Rappelez-vous, la programmation est beaucoup de choses, dont une attention particulière aux détails ... :-)length
n'est pas une méthode). :-)Remarque : Cette réponse est désespérément obsolète. Pour une approche plus moderne, regardez les méthodes disponibles sur un tableau . Les méthodes d'intérêt peuvent être:
La manière standard d'itérer un tableau en JavaScript est une
for
boucle vanille :Notez cependant que cette approche n'est bonne que si vous avez un tableau dense et que chaque index est occupé par un élément. Si le tableau est clairsemé, vous pouvez rencontrer des problèmes de performances avec cette approche, car vous itérerez sur un grand nombre d'indices qui n'existent pas vraiment dans le tableau. Dans ce cas, une
for .. in
boucle pourrait être une meilleure idée. Cependant , vous devez utiliser les protections appropriées pour vous assurer que seules les propriétés souhaitées du tableau (c'est-à-dire les éléments du tableau) sont prises en compte, car lafor..in
boucle -lo sera également énumérée dans les navigateurs hérités ou si les propriétés supplémentaires sont définies commeenumerable
.Dans ECMAScript 5, il y aura une méthode forEach sur le prototype de la baie, mais elle n'est pas prise en charge dans les navigateurs hérités. Donc, pour pouvoir l'utiliser de manière cohérente, vous devez soit avoir un environnement qui le prend en charge (par exemple, Node.js pour JavaScript côté serveur), soit utiliser un "Polyfill". Le Polyfill pour cette fonctionnalité est cependant trivial et comme il rend le code plus facile à lire, c'est un bon polyfill à inclure.
la source
for(instance in objArray)
pas une utilisation correcte? cela me semble plus simple, mais j'entends que vous en parlez comme un moyen incorrect d'utilisation?var
mot-clé. Si nous avions utilisé un point-virgule, alorselement
il aurait été déclaré dans la portée globale (ou, plutôt, JSHint nous aurait crié dessus avant qu'il n'atteigne la production).Si vous utilisez la bibliothèque jQuery , vous pouvez utiliser jQuery.each :
ÉDITER :
Selon la question, l'utilisateur veut du code en javascript au lieu de jquery donc la modification est
la source
Boucle en arrière
Je pense que l' inverse de la boucle mérite une mention ici:
Avantages:
len
variable temporaire ou de comparer avecarray.length
à chaque itération, l'une ou l'autre pouvant être une minute d'optimisation.array[i]
), alors une boucle directe ignorerait l'élément qui s'est déplacé vers la gauche en position i , ou retraiter le i ème élément qui était déplacé vers la droite. Dans une boucle for traditionnelle, vous pouvez mettre à jour i pour pointer vers l'élément suivant qui doit être traité - 1, mais simplement inverser le sens de l'itération est souvent une solution plus simple et plus élégante .forEach()
et aux ES6for ... of
.Désavantages:
Dois-je toujours l'utiliser?
Certains développeurs utilisent l'inverse pour la boucle par défaut , sauf s'il existe une bonne raison de boucler vers l'avant.
Bien que les gains de performances soient généralement insignifiants, cela crie en quelque sorte:
Cependant, dans la pratique, ce n'est pas réellement une indication fiable de l'intention, car il est impossible de les distinguer des occasions où vous vous souciez de la commande et avez vraiment besoin de boucler en sens inverse. Donc, en fait, une autre construction serait nécessaire pour exprimer avec précision l'intention de "ne pas s'en soucier", quelque chose actuellement indisponible dans la plupart des langues, y compris ECMAScript, mais qui pourrait être appelé, par exemple,
forEachUnordered()
,.Si l'ordre n'a pas d'importance et que l' efficacité est une préoccupation (dans la boucle la plus profonde d'un moteur de jeu ou d'animation), il peut être acceptable d'utiliser l'inverse pour la boucle comme modèle de référence. N'oubliez pas que voir une boucle inverse pour dans le code existant ne signifie pas nécessairement que l'ordre n'est pas pertinent!
Il valait mieux utiliser forEach ()
En général, pour le code de niveau supérieur où la clarté et la sécurité sont des préoccupations plus importantes, j'ai précédemment recommandé d'utiliser
Array::forEach
comme modèle par défaut pour la boucle (bien que de nos jours je préfère utiliserfor..of
). Les raisons de préférerforEach
une boucle inversée sont:for
etwhile
).Ensuite, lorsque vous voyez l'inverse de la boucle dans votre code, c'est un indice qu'il est inversé pour une bonne raison (peut-être l'une des raisons décrites ci-dessus). Et le fait de voir une boucle avant traditionnelle peut indiquer que le décalage peut avoir lieu.
(Si la discussion de l'intention n'a aucun sens pour vous, alors vous et votre code pourriez bénéficier de regarder la conférence de Crockford sur le style de programmation et votre cerveau .)
Il est maintenant encore mieux d'utiliser for..of!
Il y a un débat pour savoir si
for..of
ouforEach()
sont préférables:Pour une prise en charge maximale du navigateur,
for..of
nécessite un polyfill pour les itérateurs, ce qui rend votre application légèrement plus lente à exécuter et légèrement plus grande à télécharger.Pour cette raison (et pour encourager l'utilisation de
map
etfilter
), certains guides de style frontaux interdisentfor..of
complètement!Mais les préoccupations ci-dessus ne s'appliquent pas aux applications Node.js, où elles
for..of
sont désormais bien prises en charge.Et en plus
await
ne fonctionne pas à l' intérieurforEach()
. L'utilisationfor..of
est le modèle le plus clair dans ce cas.Personnellement, j'ai tendance à utiliser ce qui semble le plus facile à lire, sauf si les performances ou la minification sont devenues une préoccupation majeure. Donc, ces jours-ci, je préfère utiliser
for..of
au lieu deforEach()
, mais j'utiliserai toujoursmap
oufilter
oufind
ousome
lorsque cela s'applique. (Pour le bien de mes collègues, j'utilise rarementreduce
.)Comment ça marche?
Vous remarquerez que
i--
c'est la clause du milieu (où nous voyons généralement une comparaison) et la dernière clause est vide (où nous voyons généralementi++
). Cela signifie que celai--
est également utilisé comme condition de poursuite. Fondamentalement, il est exécuté et vérifié avant chaque itération.Comment peut-il commencer
array.length
sans exploser?Parce qu'il
i--
s'exécute avant chaque itération, lors de la première itération, nous accèderons en fait à l'élémentarray.length - 1
auquel vous éviterez tout problème avec les élémentshors limitesundefined
.Pourquoi ne cesse-t-il pas d'itérer avant l'index 0?
La boucle cesse d'itérer lorsque la condition est
i--
évaluée à une valeur de falsey (lorsqu'elle donne 0).L'astuce est que, contrairement à
--i
, l'i--
opérateur de fin décrémentei
mais donne la valeur avant la décrémentation. Votre console peut le démontrer:> var i = 5; [i, i--, i];
[5, 5, 4]
Donc, la dernière itération, j'étais auparavant 1 et l' expression il passe à 0 , mais les rendements en fait 1 (truthy), et donc la condition passe. À l'itération suivante , i passe à -1 mais donne 0 (falsey), ce qui fait que l'exécution tombe immédiatement du bas de la boucle.
i--
i--
Dans les forwards traditionnels pour la boucle,
i++
et++i
sont interchangeables (comme le souligne Douglas Crockford). Cependant, dans le sens inverse de la boucle, car notre décrément est également notre expression de condition, nous devons nous en teniri--
si nous voulons traiter l'élément à l'index 0.Trivia
Certaines personnes aiment dessiner une petite flèche dans la
for
boucle inverse et terminer avec un clin d'œil:Les crédits vont à WYL pour m'avoir montré les avantages et les horreurs du reverse for loop.
la source
Certains langages de style C permettent
foreach
de parcourir les énumérations. En JavaScript, cela se fait avec lafor..in
structure de la boucle :Il y a un hic.
for..in
parcourra chacun des membres énumérables de l'objet et les membres de son prototype. Pour éviter de lire les valeurs héritées du prototype de l'objet, vérifiez simplement si la propriété appartient à l'objet:De plus, ECMAScript 5 a ajouté une
forEach
méthodeArray.prototype
qui peut être utilisée pour énumérer un tableau à l'aide d'un calback (le polyfill est dans les documents afin que vous puissiez toujours l'utiliser pour les navigateurs plus anciens):Il est important de noter que
Array.prototype.forEach
cela ne se casse pas lorsque le rappel revientfalse
. jQuery et Underscore.js fournissent leurs propres variationseach
pour fournir des boucles qui peuvent être court-circuitées.la source
each
méthodes qui permettentreturn false
d'être utilisées pour sortir de la boucle, mais avecforEach
ce n'est pas une option. Un indicateur externe pourrait être utilisé (c'est-àif (flag) return;
- dire , mais cela empêcherait uniquement le reste du corps de la fonction de s'exécuter,forEach
continuerait à itérer sur toute la collection.Si vous souhaitez boucler sur un tableau, utilisez la
for
boucle en trois parties standard .Vous pouvez obtenir des optimisations de performances en mettant en cache
myArray.length
ou en itérant en arrière.la source
length
. ;),
après une affectation n'introduit pas de nouveau global, donc votre suggestion est très bien ! Je confondais cela pour un problème différent: l'utilisation=
après une affectation crée un nouveau global.var i, length, arrayItem;
avant la boucle pour éviter ce malentendu.Je sais que c'est un vieux post, et il y a déjà tellement de bonnes réponses. Pour un peu plus d'exhaustivité, j'ai pensé que j'en jetterais un autre en utilisant AngularJS . Bien sûr, cela ne s'applique que si vous utilisez Angular, évidemment, j'aimerais quand même le dire.
angular.forEach
prend 2 arguments et un troisième argument facultatif. Le premier argument est l'objet (tableau) sur lequel itérer, le deuxième argument est la fonction itérateur, et le troisième argument facultatif est le contexte de l'objet (appelé fondamentalement à l'intérieur de la boucle «this»).Il existe différentes façons d'utiliser la boucle forEach d'angular. Le plus simple et probablement le plus utilisé est
Une autre méthode utile pour copier des éléments d'un tableau vers un autre est
Bien que vous n'ayez pas à le faire, vous pouvez simplement faire ce qui suit et c'est équivalent à l'exemple précédent:
Il y a maintenant des avantages et des inconvénients à utiliser la
angular.forEach
fonction par opposition à la fonction intégrée à la vanillefor
boucle .Avantages
angular.forEach
utilisera la boucle ES5 forEach. Maintenant, j'arriverai à l'efficacité dans la section contre, car les boucles forEach sont beaucoup plus lentes que les boucles for. Je le mentionne en tant que pro car c'est agréable d'être cohérent et standardisé.Considérez les 2 boucles imbriquées suivantes, qui font exactement la même chose. Disons que nous avons 2 tableaux d'objets et que chaque objet contient un tableau de résultats, dont chacun a une propriété Value qui est une chaîne (ou autre). Et disons que nous devons répéter chacun des résultats et s'ils sont égaux, effectuez une action:
Certes, c'est un exemple hypothétique très simple, mais j'ai écrit triple intégré pour les boucles en utilisant la deuxième approche et il était très difficile à lire et à écrire d'ailleurs.
Les inconvénients
angular.forEach
, et le natifforEach
, d'ailleurs, sont tous deux beaucoup plus lents que lafor
boucle normale ... environ 90% plus lents . Donc, pour les grands ensembles de données, mieux vaut s'en tenir à lafor
boucle native .continue
est en fait pris en charge par " accident ", pour continuer dans unangular.forEach
simple, mettez unereturn;
instruction dans la fonction commeangular.forEach(array, function(item) { if (someConditionIsTrue) return; });
ce qui la fera sortir de la fonction pour cette itération. Cela est également dû au fait que le natifforEach
ne prend pas en charge la pause ou la poursuite non plus.Je suis sûr qu'il existe également d'autres avantages et inconvénients, et n'hésitez pas à ajouter ceux que vous jugez appropriés. Je pense que, en fin de compte, si vous avez besoin d'efficacité, restez avec la
for
boucle native pour vos besoins de boucle. Mais, si vos jeux de données sont plus petits et qu'une certaine efficacité est acceptable pour abandonner en échange de la lisibilité et de l'écriture, alors par tous les moyens, jetez unangular.forEach
mauvais garçon.la source
Si cela ne vous dérange pas de vider le tableau:
x
contiendra la dernière valeur dey
et sera supprimée du tableau. Vous pouvez également utilisershift()
ce qui donnera et supprimera le premier élément dey
.la source
[1, 2, undefined, 3]
.[1, 2, 0, 3]
ou[true, true, false, true]
Une implémentation forEach ( voir dans jsFiddle ):
la source
La
for(i = 0; i < array.length; i++)
boucle n'est probablement pas le meilleur choix. Pourquoi? Si vous avez ceci:La méthode appellera de
array[0]
àarray[2]
. Premièrement, cela référencera d'abord les variables que vous n'avez même pas, deuxièmement vous n'aurez pas les variables dans le tableau, et troisièmement cela rendra le code plus audacieux. Regardez ici, c'est ce que j'utilise:Et si vous voulez que ce soit une fonction, vous pouvez le faire:
Si vous voulez casser, un peu plus de logique:
Exemple:
Il renvoie:
la source
Il existe trois implémentations de
foreach
dans jQuery comme suit.la source
Depuis ECMAScript 6:
Où
of
évite les bizarreries associéesin
et le fait fonctionner comme lafor
boucle de toute autre langue, etlet
liei
à l'intérieur de la boucle plutôt qu'à l'intérieur de la fonction.Les accolades (
{}
) peuvent être omises lorsqu'il n'y a qu'une seule commande (par exemple dans l'exemple ci-dessus).la source
Une solution simple serait maintenant d'utiliser la bibliothèque underscore.js . Il fournit de nombreux outils utiles, tels que
each
et déléguera automatiquement le travail au natifforEach
si disponible.Voici un exemple de fonctionnement de CodePen :
Voir également
Array.prototype.forEach()
.for each (variable in object)
est déconseillé de faire partie de la norme ECMA-357 ( EAX ).for (variable of object)
dans le cadre de la proposition Harmony (ECMAScript 6).la source
Il n'y a pas de
for each
boucle en JavaScript natif . Vous pouvez soit utiliser des bibliothèques pour obtenir cette fonctionnalité (je recommande Underscore.js ), utiliser unefor
boucle simple .Cependant, notez qu'il peut y avoir des raisons d'utiliser une
for
boucle encore plus simple (voir la question de débordement de pile Pourquoi l'utilisation de «for… in» avec l'itération du tableau est-elle une si mauvaise idée? )la source
Il s'agit d'un itérateur pour la liste NON clairsemée où l'index commence à 0, ce qui est le scénario typique lors du traitement de document.getElementsByTagName ou document.querySelectorAll)
Exemples d'utilisation:
Exemple 1
Exemple # 2
Chaque balise p obtient
class="blue"
Exemple # 3
Chaque autre balise p obtient
class="red"
>Exemple # 4
Et enfin, les 20 premières balises p bleues sont passées au vert
Attention lorsque vous utilisez une chaîne comme fonction: la fonction est créée hors contexte et ne doit être utilisée que lorsque vous êtes certain de la portée des variables. Sinon, mieux vaut passer des fonctions où la portée est plus intuitive.
la source
Il existe plusieurs façons de parcourir un tableau en JavaScript, comme ci-dessous:
car - c'est le plus courant . Bloc complet de code pour le bouclage
while - boucle pendant qu'une condition est remplie. Cela semble être la boucle la plus rapide
do / while - boucle également à travers un bloc de code pendant que la condition est vraie, s'exécutera au moins une fois
Boucles fonctionnelles -
forEach
,map
,filter
aussireduce
(ils boucle par la fonction, mais ils sont utilisés si vous avez besoin de faire quelque chose avec votre tableau, etc.Pour plus d'informations et d'exemples sur la programmation fonctionnelle sur les tableaux, consultez le billet de blog Programmation fonctionnelle en JavaScript: mapper, filtrer et réduire .
la source
forEach
n'est pas une boucle "fonctionnelle" car elle ne retourne pas de nouvelleArray
(en fait elle ne retourne rien), elle ne fait qu'itérer.ECMAScript 5 (la version sur JavaScript) pour travailler avec les tableaux:
forEach - Parcourt chaque élément du tableau et fait tout ce dont vous avez besoin avec chaque élément.
Dans le cas, plus intéressé par le fonctionnement sur la baie en utilisant une fonctionnalité intégrée.
map - Il crée un nouveau tableau avec le résultat de la fonction de rappel. Cette méthode peut être utilisée lorsque vous devez formater les éléments de votre tableau.
réduire - Comme son nom l'indique, il réduit le tableau à une seule valeur en appelant la fonction donnée en passant dans l'élément en cours et le résultat de l'exécution précédente.
every - Renvoie vrai ou faux si tous les éléments du tableau réussissent le test dans la fonction de rappel.
filter - Très similaire à tous sauf que filter retourne un tableau avec les éléments qui retournent true à la fonction donnée.
la source
Il n'y a aucune capacité intrinsèque à s'introduire
forEach
. Pour interrompre l'exécution, utilisez ce quiArray#some
suit:Cela fonctionne car
some
renvoie true dès que l'un des rappels, exécuté dans l'ordre du tableau, retourne true, court-circuitant l'exécution du reste. Réponse originale, voir prototype Array pour certainsla source
Je voudrais également ajouter cela comme une composition d'une boucle inverse et une réponse ci-dessus pour quelqu'un qui aimerait cette syntaxe aussi.
Avantages:
L'avantage pour cela: vous avez déjà la référence dans la première comme celle-ci qui n'aura pas besoin d'être déclarée plus tard avec une autre ligne. C'est pratique lors de la boucle à travers le tableau d'objets.
Les inconvénients:
Cela se cassera chaque fois que la référence est fausse - falsey (non défini, etc.). Il peut cependant être utilisé comme un avantage. Cependant, cela rendrait la lecture un peu plus difficile. De plus, selon le navigateur, il peut être "non" optimisé pour fonctionner plus rapidement que celui d'origine.
la source
manière jQuery en utilisant
$.map
:la source
[undefined, 2, undefined, 4, undefined, 6, undefined]
.Utilisation de boucles avec la déstructuration ECMAScript 6 et l' opérateur d'étalement
La déstructuration et l'utilisation de l'opérateur de diffusion se sont révélées très utiles pour les nouveaux arrivants à ECMAScript 6 car elles sont plus lisibles / esthétiques, bien que certains vétérans de JavaScript puissent le considérer comme désordonné. Les juniors ou d'autres personnes pourraient trouver cela utile.
Exemple 1:
for...of
boucle normale - pas d'astuces ici.Exemple 2: fractionner des mots en caractères
Exemple 3: boucle avec a
key
etvalue
Exemple 4: obtenir les propriétés d'objet en ligne
Exemple 5: Obtenez des propriétés d'objet détaillées de ce dont vous avez besoin
Exemple 6: Est Exemple 3 utilisé avec
.forEach
Exemple 7: Est Exemple 4 utilisé avec
.forEach
Exemple 8: Est exemple 5 utilisé avec
.forEach
la source
Un moyen le plus proche de votre idée serait d'utiliser
Array.forEach()
qui accepte une fonction de fermeture qui sera exécutée pour chaque élément du tableau.Une autre façon viable serait d'utiliser
Array.map()
ce qui fonctionne de la même manière, mais il prend également toutes les valeurs que vous renvoyez et les renvoie dans un nouveau tableau (mappant essentiellement chaque élément à un nouveau), comme ceci:la source
map
cela ne mute pas les éléments du tableau, car il renvoie un nouveau tableau, les éléments de ce nouveau étant le résultat de l'application de la fonction aux éléments de l'ancien tableau.Vous pouvez appeler chacun comme ceci:
forEach
itérera sur le tableau que vous fournissez et pour chaque itération qu'il aura,element
qui contient la valeur de cette itération. Si vous avez besoin d'un index, vous pouvez obtenir l'index actuel en passanti
le second paramètre dans la fonction de rappel de forEach.Foreach est fondamentalement une fonction d'ordre élevé, qui prend une autre fonction comme paramètre.
Production:
Vous pouvez également parcourir un tableau comme celui-ci:
la source
Si vous souhaitez parcourir un tableau d'objets avec la fonction flèche:
la source
La syntaxe lambda ne fonctionne généralement pas dans Internet Explorer 10 ou inférieur.
J'utilise habituellement le
Si vous êtes un fan de jQuery et que vous avez déjà un fichier jQuery en cours d'exécution, vous devez inverser les positions des paramètres d'index et de valeur
la source
Si vous disposez d'un réseau massif, vous devez l'utiliser
iterators
pour gagner en efficacité. Itérateurs sont une propriété de certaines collections de JavaScript (commeMap
,Set
,String
,Array
). Même,for..of
utiliseiterator
sous le capot.Les itérateurs améliorent l'efficacité en vous permettant de consommer les éléments d'une liste un par un comme s'ils étaient un flux. Ce qui rend un itérateur spécial, c'est comment il parcourt une collection. D'autres boucles doivent charger la collection entière à l'avance afin d'itérer dessus, alors qu'un itérateur n'a besoin que de connaître la position actuelle dans la collection.
Vous accédez à l'élément en cours en appelant la
next
méthode de l'itérateur . La méthode suivante renverra levalue
de l'élément actuel et unboolean
pour indiquer quand vous avez atteint la fin de la collection. Voici un exemple de création d'un itérateur à partir d'un tableau.Transformez votre tableau régulier en itérateur en utilisant une
values()
méthode comme celle-ci:Vous pouvez également transformer votre tableau régulier en itérateur en utilisant
Symbol.iterator
comme ceci:Vous pouvez également transformer votre habitué
array
en uniterator
modèle comme celui-ci:REMARQUE :
iterable
par défaut. À utiliserfor..in
dans ce cas, car au lieu de valeurs, il fonctionne avec des clés.Vous pouvez en savoir plus
iteration protocol
ici .la source
Si vous souhaitez utiliser
forEach()
, cela ressemblera à -Si vous souhaitez utiliser
for()
, cela ressemblera à -la source
Conformément à la nouvelle fonctionnalité mise à jour ECMAScript 6 (ES6) et ECMAScript 2015, vous pouvez utiliser les options suivantes avec des boucles:
la source
Performance
Aujourd'hui (18/12/2019), j'effectue un test sur mon macOS v10.13.6 (High Sierra), sur Chrome v 79.0, Safari v13.0.4 et Firefox v71.0 (64 bits) - conclusions sur l'optimisation (et la micro-optimisation qui il n'est généralement pas utile de l'introduire dans le code car l'avantage est faible, mais la complexité du code augmente).
Il semble que le traditionnel
for i
( Aa ) soit un bon choix pour écrire du code rapide sur tous les navigateurs.Les autres solutions, comme
for-of
( Ad ), toutes dans le groupe C. ... sont généralement 2 à 10 (et plus) plus lentes que Aa , mais pour les petits tableaux, il est correct de les utiliser - pour augmenter la clarté du code.Les boucles de longueur de tableau mises en cache dans
n
( Ab, Bb, Be ) sont parfois plus rapides, parfois non. Les compilateurs détectent probablement cette situation et introduisent la mise en cache. Les différences de vitesse entre les versions en cache et sans cache ( Aa, Ba, Bd ) sont d'environ ~ 1%, il semble donc que l'introductionn
soit une micro-optimisation .Les
i--
solutions similaires où la boucle commence à partir du dernier élément du tableau ( Ac, Bc ) sont généralement ~ 30% plus lentes que les solutions directes - probablement la raison est le mode de fonctionnement du cache de la mémoire CPU - la lecture de la mémoire directe est plus optimale pour la mise en cache CPU). Il est recommandé de NE PAS UTILISER de telles solutions.Détails
Dans les tests, nous calculons la somme des éléments du tableau. J'effectue un test pour les petits tableaux (10 éléments) et les grands tableaux (1 M éléments) et les divise en trois groupes:
for
testswhile
testsAfficher l'extrait de code
Résultats de plusieurs navigateurs
Résultats pour tous les navigateurs testés
navigateurs **
Tableau avec 10 éléments
Résultats pour Chrome. Vous pouvez effectuer le test sur votre machine ici .
Tableau avec 1 000 000 d'éléments
Résultats pour Chrome. Vous pouvez effectuer le test sur votre machine ici
la source
Sommaire:
Lors de l'itération sur un tableau, nous souhaitons souvent atteindre l'un des objectifs suivants:
Nous voulons parcourir le tableau et créer un nouveau tableau:
Array.prototype.map
Nous voulons parcourir le tableau et ne pas créer de nouveau tableau:
Array.prototype.forEach
for..of
boucleEn JavaScript, il existe de nombreuses façons d'atteindre ces deux objectifs. Cependant, certains sont plus pratiques que d'autres. Vous trouverez ci-dessous quelques méthodes couramment utilisées (l'IMO la plus pratique) pour effectuer l'itération de tableau en JavaScript.
Création d'un nouveau tableau:
Map
map()
est une fonction située surArray.prototype
laquelle peut transformer chaque élément d'un tableau, puis retourne un nouveau tableau.map()
prend comme argument une fonction de rappel et fonctionne de la manière suivante:Le rappel dans lequel nous sommes passés
map()
comme argument est exécuté pour chaque élément. Ensuite, un tableau est renvoyé qui a la même longueur que le tableau d'origine. Dans ce nouvel élément de tableau est transformé par la fonction de rappel passée en argument àmap()
.La différence distincte entre
map
et un autre mécanisme de boucle commeforEach
et unefor..of
boucle est quemap
renvoie un nouveau tableau et laisse l'ancien tableau intact (sauf si vous le manipulez explicitement avec pense commesplice
).Notez également que le
map
rappel de la fonction fournit le numéro d'index de l'itération en cours comme deuxième argument. De plus, le troisième argument fournit-il le tableau sur lequel amap
été appelé? Parfois, ces propriétés peuvent être très utiles.Boucle utilisant
forEach
forEach
est une fonction qui se trouve surArray.prototype
laquelle prend une fonction de rappel comme argument. Il exécute ensuite cette fonction de rappel pour chaque élément du tableau. Contrairement à lamap()
fonction, la fonction forEach ne renvoie rien (undefined
). Par exemple:Tout comme la
map
fonction, leforEach
rappel fournit le numéro d'index de l'itération en cours comme deuxième argument. De plus, le troisième argument fournit-il le tableau sur lequel aforEach
été appelé?Parcourez les éléments en utilisant
for..of
La
for..of
boucle parcourt chaque élément d'un tableau (ou tout autre objet itérable). Cela fonctionne de la manière suivante:Dans l'exemple ci-dessus,
element
représente un élément de tableau etarr
est le tableau que nous voulons boucler. Notez que le nomelement
est arbitraire, et nous aurions pu choisir n'importe quel autre nom comme 'el' ou quelque chose de plus déclaratif lorsque cela est applicable.Ne confondez pas la
for..in
boucle avec lafor..of
boucle.for..in
parcourra toutes les propriétés énumérables du tableau tandis que lafor..of
boucle ne parcourra que les éléments du tableau. Par exemple:la source