Pour chacun sur un tableau en JavaScript

4684

Comment puis-je parcourir toutes les entrées d'un tableau à l'aide de JavaScript?

Je pensais que c'était quelque chose comme ça:

forEach(instance in theArray)

theArrayest mon tableau, mais cela semble être incorrect.

Dante1986
la source
16
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.
Slaven Rezic
36
Array.ForEach est environ 95% plus lent que for () in pour chacun des tableaux en JavaScript. Voir ce test de performance en ligne: jsperf.com/fast-array-foreach via coderwall.com/p/kvzbpa
molokoloco
77
Pour de nombreuses situations, un ralentissement de 95% ne sera pas significatif blog.niftysnippets.org/2012/02/foreach-and-runtime-cost.html
David Sykes
7
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.
  • Vos meilleurs paris sont généralement

    • une for-ofboucle (ES2015 + uniquement),
    • Array#forEach( spec| MDN) (ou ses proches someet autres) (ES5 + uniquement),
    • une simple forboucle à l' ancienne ,
    • ou for-inavec 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' 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"):

  1. Utilisation forEachet connexes (ES5 +)
  2. Utilisez une forboucle simple
  3. Utiliser for-in correctement
  4. Utiliser for-of(utiliser un itérateur implicitement) (ES2015 +)
  5. 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]);
}

Et / ou en comptant à rebours:

var index;
var a = ["a", "b", "c"];
for (index = a.length - 1; index >= 0; --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"

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);
    });
}

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-in correctement

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:

  • Il est un clairsemés des réseaux avec d' énormes lacunes dans, ou
  • 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 array
var 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]);
    }
}

Notez les trois contrôles:

  1. Que l'objet a sa propre propriété de ce nom (pas celle qu'il hérite de son prototype), et

  2. 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

  3. 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:

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-ofinstruction. Cela ressemble à ceci:

const a = ["a", "b", "c"];
for (const val of a) {
    console.log(val);
}

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:

  1. 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.)

    Supposons que vous vouliez utiliser forEachsur Nodedes » childNodesbiens. Vous feriez ceci:

    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`
    });
  2. Utilisez une forboucle simple

    De toute évidence, une simple forboucle s'applique aux objets de type tableau.

  3. Utiliser for-in correctement

    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.

  4. 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.

  5. 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:

  1. 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.

  2. 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")];
  3. 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.)

TJ Crowder
la source
44
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.

PatrikAkerstrand
la source
2
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].
}
Poonam
la source
2
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..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 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.

  • Et en plus await ne fonctionne pas à l' intérieur forEach(). L'utilisation for..ofest 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..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++) { ... }   // Forwards

for (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.

  • Comment peut-il commencer array.lengthsans 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ément array.length - 1auquel vous éviterez tout problème avec les éléments hors limites undefined .

  • 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.

joeytwiddle
la source
3
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).
joeytwiddle
84

Certains langages de style C permettent foreachde parcourir les énumérations. En JavaScript, cela se fait avec la for..instructure de la boucle :

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):

arr.forEach(function (val, index, theArray) {
    //do stuff
});

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.

zzzzBov
la source
3
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.

Quentin
la source
6
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:

angular.forEach(temp, function(item) {
    temp2.push(item);
});

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 loop
for (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.

user2359695
la source
34

Si cela ne vous dérange pas de vider le tableau:

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.

gaby de wilde
la source
4
Cela ne fonctionne pas si vous avez un tableau clairsemé comme [1, 2, undefined, 3].
M. Grzywaczewski
2
... ou bien n'importe quoi falsey: [1, 2, 0, 3]ou[true, true, false, true]
joeytwiddle
31

Une implémentation forEach ( voir dans jsFiddle ):

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
  }
);
nmoliveira
la source
2
itérateur dans ce domaine, fait un calcul de longueur inutile. Dans un cas idéal, la longueur de la liste ne devrait être calculée qu'une seule fois.
MIdhun Krishna
2
@MIdhunKrishna J'ai mis à jour ma réponse et le jsFiddle mais sachez que ce n'est pas aussi simple que vous le pensez. Cochez cette question
nmoliveira
2
L'implémentation complète et correcte peut être trouvée ici: developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
marciowb
29

La for(i = 0; i < array.length; i++)boucle n'est probablement pas le meilleur choix. Pourquoi? Si vous avez ceci:

var array = new Array();
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;
        }
    }
}

Exemple:

foreach(array, function(el){
    if(el != "!"){
        console.log(el);
    } else {
        console.log(el+"!!");
    }
});

Il renvoie:

//Hello
//World
//!!!
Federico Piragua
la source
29

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
Rajesh Paul
la source
2
Le journal de la console est juste pour la démo. C'est pour en faire un exemple de fonctionnement complet.
Rajesh Paul
29

Depuis ECMAScript 6:

list = [0, 1, 2, 3]
for (let obj of list) {
    console.log(obj)
}

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).

Zaz
la source
28

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.

Voici un exemple de fonctionnement de CodePen :

var arr = ["elemA", "elemB", "elemC"];
_.each(arr, function(elem, index, ar)
{
...
});

Voir également

Micka
la source
23

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 .

for (var instance in objects) {
   ...
}

Cependant, notez qu'il peut y avoir des raisons d'utiliser une forboucle 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? )

var instance;
for (var i=0; i < objects.length; i++) {
    var instance = objects[i];
    ...
}
joidegn
la source
22

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 );   

    return this;
}

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]

Exemple # 2

each.call(document.getElementsByTagName('p'), "this.className = data;",'blue');

Chaque balise p obtient class="blue"

Exemple # 3

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.

Tim
la source
21

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;
<p id="example"></p>

while - boucle pendant qu'une condition est remplie. Cela semble être la boucle la plus rapide

var text = "";
var i = 0;
while (i < 10) {
    text +=  i + ") something<br>";
    i++;
}
document.getElementById("example").innerHTML = text;
<p id="example"></p>

do / while - boucle également à travers un bloc de code pendant que la condition est vraie, s'exécutera au moins une fois

var text = ""
var i = 0;

do {
    text += i + ") something <br>";
    i++;
}
while (i < 10);

document.getElementById("example").innerHTML = text;
<p id="example"></p>

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 function
var numbers = [65, 44, 12, 4];
document.getElementById("example").innerHTML = numbers.map(function(num){return num * 2});
<p id="example"></p>

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 .

Alireza
la source
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.

[1,2,3,4].reduce(function(previous, current) {
  return previous + current;
});
// Output: 10
// 1st iteration: previous=1, current=2 => result=3
// 2nd iteration: previous=3, current=3 => result=6
// 3rd iteration: previous=6, current=4 => result=10

every - Renvoie vrai ou faux si tous les éléments du tableau réussissent le test dans la fonction de rappel.

// Check if everybody has 18 years old of more.
var ages = [30, 43, 18, 5];
ages.every(function(elem) {
  return elem >= 18;
});

// Output: false

filter - Très similaire à tous sauf que filter retourne un tableau avec les éléments qui retournent true à la fonction donnée.

// Finding the even numbers
[1,2,3,4,5,6].filter(function(elem){
  return (elem % 2 == 0)
});

// Output: [2,4,6]
Anil Kumar Arya
la source
16

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

Priyanshu Chauhan
la source
13

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.

Volkan Seçkin Akbayır
la source
12

manière jQuery en utilisant $.map:

var data = [1, 2, 3, 4, 5, 6, 7];

var newData = $.map(data, function(element) {
    if (element % 2 == 0) {
        return element;
    }
});

// newData = [2, 4, 6];
Daniel W.
la source
1
Je pense que la sortie est plus susceptible d'être [undefined, 2, undefined, 4, undefined, 6, undefined].
10

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.

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);
}

Exemple 2: fractionner des mots en caractères

let arrFruits = ['apple', 'orange', 'banana'];

for (let [firstLetter, ...restOfTheWord] of arrFruits) {
  // Create a shallow copy using the spread operator
  let [lastLetter] = [...restOfTheWord].reverse();
  console.log(firstLetter, lastLetter, restOfTheWord);
}

Exemple 3: boucle avec a keyetvalue

// 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);
}

Exemple 4: obtenir les propriétés d'objet en ligne

let arrWithObjects = [{
    name: 'Jon',
    age: 32
  },
  {
    name: 'Elise',
    age: 33
  }
];

for (let { name, age: aliasForAge } of arrWithObjects) {
  console.log(name, aliasForAge);
}

Exemple 5: Obtenez des propriétés d'objet détaillées de ce dont vous avez besoin

let arrWithObjectsWithArr = [{
    name: 'Jon',
    age: 32,
    tags: ['driver', 'chef', 'jogger']
  },
  {
    name: 'Elise',
    age: 33,
    tags: ['best chef', 'singer', 'dancer']
  }
];

for (let { name, tags: [firstItemFromTags, ...restOfTags] } of arrWithObjectsWithArr) {
  console.log(name, firstItemFromTags, restOfTags);
}

Exemple 6: Est Exemple 3 utilisé avec.forEach

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);
});

Exemple 7: Est Exemple 4 utilisé avec.forEach

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)
});

Exemple 8: Est exemple 5 utilisé avec.forEach

let arrWithObjectsWithArr = [{
    name: 'Jon',
    age: 32,
    tags: ['driver', 'chef', 'jogger']
  },
  {
    name: 'Elise',
    age: 33,
    tags: ['best chef', 'singer', 'dancer']
  }
];

arrWithObjectsWithArr.forEach(({
  name,
  tags: [firstItemFromTags, ...restOfTags]
}) => {
  console.log(name, firstItemFromTags, restOfTags);
});

darklightcode
la source
7

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:

var myArray = [1, 2, 3];
myArray = myArray.map(
  (item) => {
    return item + 1;
  }
);

console.log(myArray); // [2, 3, 4]
Ante Jablan Adamović
la source
1
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:

1
3
2

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
}
Nouman Dilshad
la source
6

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');
})

subhashish negi
la source
6

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);
});
Murtuza Husain
la source
5

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());

Vous pouvez également transformer votre tableau régulier en itérateur en utilisant Symbol.iteratorcomme ceci:

const myArr = [2,3,4]

let it = myArr[Symbol.iterator]();

console.log(it.next());
console.log(it.next());
console.log(it.next());
console.log(it.next());

Vous pouvez également transformer votre habitué arrayen un iteratormodèle comme celui-ci:

let myArr = [8, 10, 12];

function makeIterator(array) {
    var nextIndex = 0;
    
    return {
       next: function() {
           return nextIndex < array.length ?
               {value: array[nextIndex++], done: false} :
               {done: true};
       }
    };
};

var it = makeIterator(myArr);

console.log(it.next().value);   // {value: 8, done: false}
console.log(it.next().value);   // {value: 10, done: false}
console.log(it.next().value);   // {value: 12, done: false}
console.log(it.next().value);   // {value: undefined, done: true}

REMARQUE :

  • Les itérateurs sont de nature épuisable.
  • Les objets ne sont pas iterablepar défaut. À utiliser for..indans ce cas, car au lieu de valeurs, il fonctionne avec des clés.

Vous pouvez en savoir plus iteration protocol ici .

Blackeard
la source
5

Si vous souhaitez utiliser forEach(), cela ressemblera à -

theArray.forEach ( element => {
    console.log(element);
});

Si vous souhaitez utiliser for(), cela ressemblera à -

for(let idx = 0; idx < theArray.length; idx++){
    let element = theArray[idx];
    console.log(element);
}
Harunur Rashid
la source
4

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 = 0

while(x < 5){
  console.log(x)
  x++
}

// Output: 1,2,3,4

faire ... tandis que les boucles

let x = 0

do{
  console.log(x)
  x++
}while(x < 5)

// Output: 1,2,3,4
ankitkanojia
la source
4

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'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:

  • A - fortests
  • B - whiletests
  • C - autres méthodes / alternatives

Résultats de plusieurs navigateurs

Résultats pour tous les navigateurs testés

Entrez la description de l'image icinavigateurs **

Tableau avec 10 éléments

Résultats pour Chrome. Vous pouvez effectuer le test sur votre machine ici .

Entrez la description de l'image ici

Tableau avec 1 000 000 d'éléments

Résultats pour Chrome. Vous pouvez effectuer le test sur votre machine ici

Entrez la description de l'image ici

Kamil Kiełczewski
la source
4

Sommaire:

Lors de l'itération sur un tableau, nous souhaitons souvent atteindre l'un des objectifs suivants:

  1. Nous voulons parcourir le tableau et créer un nouveau tableau:

    Array.prototype.map

  2. Nous voulons parcourir le tableau et ne pas créer de nouveau tableau:

    Array.prototype.forEach

    for..of boucle

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);
}

Willem van der Veen
la source