Pour-chacun sur un tableau en JavaScript?
Comment passer en boucle toutes les entrées d'un tableau en utilisant JavaScript?
je pensais que c'était quelque chose comme ça:
forEach(instance in theArray)
où theArray
est mon tableau, mais cela semble incorrect.
28 réponses
TL; DR
- N'utilisez pas
for-in
à moins que vous ne l'utilisiez avec des garanties ou que vous ne sachiez au moins pourquoi il pourrait vous mordre. -
vos meilleurs paris sont habituellement
mais il ya lots plus à explorer, lire la suite...
JavaScript possède de puissantes sémantique pour la lecture en boucle par le biais de réseaux et semblable au tableau objet. J'ai divisé la réponse en deux parties: Options pour les tableaux authentiques, et options pour les choses qui ne sont que des tableaux- comme , comme l'objet arguments
, d'autres objets itérables (ES2015+), collections DOM, et ainsi de suite.
je vais noter rapidement que vous pouvez utiliser les options ES2015 maintenant , même sur les moteurs ES5, par transposant ES2015 à ES5. Recherche de "ES2015 transpiling" / " ES6 transpiling" pour plus d'...
bon, regardons nos options:
Pour Les Tableaux Réels
vous avez trois options dans ECMAScript 5 ("ES5"), la version la plus largement supportée pour le moment, et deux autres ajoutées dans ECMAScript 2015 ("ES2015"," ES6"):
- Utiliser
forEach
et connexes (ES5+) - Utilisez une simple
for
boucle - utiliser
for-in
correctement - utiliser
for-of
(utiliser un itérateur implicitement) (ES2015+) - utiliser un itérateur explicitement (ES2015+)
détails:
1. Use forEach
et assimilé
dans tout environnement vaguement moderne (so, pas IE8) où vous avez accès aux caractéristiques Array
ajoutées par ES5 (directement ou en utilisant des polyfills), vous pouvez utiliser forEach
( spec
| MDN
):
var a = ["a", "b", "c"];
a.forEach(function(entry) {
console.log(entry);
});
forEach
accepte une fonction de rappel et, optionnellement, une valeur à utiliser comme this
lors de l'appel de ce rappel (non utilisé ci-dessus). Le callback est appelé pour chaque entrée dans le tableau, dans l'ordre, sautant les entrées inexistantes dans les tableaux épars. Bien que je n'ai utilisé qu'un seul argument ci-dessus, le callback est appelé avec trois: la valeur de chaque entrée, l'index de cette entrée, et une référence au tableau sur lequel vous itérez (au cas où votre fonction ne l'aurait pas déjà sous la main).
sauf si vous supportez des navigateurs obsolètes comme IE8 (qui NetApps montre à un peu plus de 4% de part de marché en date de cette écriture en septembre 2016), vous pouvez heureusement utiliser forEach
dans une page Web à usage général sans une minuterie. Si vous ne besoin de prendre en charge les navigateurs obsolètes, shimming/polyfilling forEach
est facilement fait (Recherche de "es5 shim" pour plusieurs options).
forEach
a l'avantage que vous n'avez pas à déclarer l'indexation et les variables de valeur dans la portée contenant, car ils sont fournis comme arguments à la fonction d'itération, et donc joliment scoped à juste cette itération.
si vous êtes inquiet du coût d'exécution d'un appel de fonction pour chaque tableau entrée, ne pas être; détails .
de plus, forEach
est la fonction "loop through them all" , mais ES5 a défini plusieurs autres fonctions utiles "work your way through the array and do things", y compris:
-
every
(arrête de boucler la première fois que le callback retournefalse
ou quelque chose falsey) -
some
(cesse de boucler la première fois que le rappel retournetrue
ou quelque chose de véridique) -
filter
(crée un nouveau tableau incluant les éléments où la fonction de filtre retournetrue
et en omettant ceux où elle retournefalse
) -
map
(crée un nouveau tableau des valeurs retournées par la fonction de rappel) -
reduce
(construit une valeur en appelant à plusieurs reprises le rappel, en passant dans les valeurs précédentes; voir la spécification pour les détails; utile pour résumer le contenu d'un tableau et bien d'autres choses) -
reduceRight
(commereduce
, mais travaille dans l'ordre décroissant plutôt que Ascendant)
2. Utilisez une simple for
boucle
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 minuscule un 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 moderne Moteurs JavaScript, il est rare que vous ayez besoin de sortir ce dernier morceau de jus.
dans ES2015 et plus, vous pouvez faire vos variables d'indice et de valeur locales à la boucle for
:
let a = ["a", "b", "c"];
for (let index = 0; index < a.length; ++index) {
let value = a[index];
}
//console.log(index); // Would cause "ReferenceError: index is not defined"
//console.log(value); // Would cause "ReferenceError: value is not defined"
et quand vous faites cela, non seulement value
mais aussi index
est recréé pour chaque itération de boucle, ce qui signifie les fermetures créées dans le corps de boucle garder une référence à la 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 => {
alert("Index is: " + index);
});
}
Si vous aviez cinq vrd, vous obtiendrez "Indice: 0" si vous avez cliqué sur le premier et "l'Index est: 4" si vous avez cliqué sur le dernier. Cela ne pas travailler si vous utilisez var
au lieu de let
.
3. Utiliser for-in
correctement
vous obtiendrez des gens qui vous diront d'utiliser for-in
, mais ce n'est pas ce que for-in
est pour . for-in
boucles à travers les énumérable propriétés d'un objet , pas les indices d'un tableau. la commande n'est pas garantie , pas même en ES2015 (ES6). ES2015 définit un ordre pour objecter des propriétés (via [[OwnPropertyKeys]]
, [[Enumerate]]
, et les choses qui les utilisent comme Object.getOwnPropertyKeys
), mais il ne fait pas définissez que for-in
suivra cet ordre. (Détails dans cette autre réponse .)
Encore, peut être utile, en particulier pour les sparse "15191730920 des" tableaux , si vous utilisez des garanties 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 are explained
/^0$|^[1-9]\d*$/.test(key) && // and then hidden
key <= 4294967294 // away below
) {
console.log(a[key]);
}
}
notez les deux contrôles:
-
que l'objet a son propre ,
et ."
-
que la clé est une chaîne de base-10 numérique dans sa forme de chaîne normale et sa valeur est <= 2^32 - 2 (qui est 4,294,967,294). Où est-ce que le numéro de venir? Il 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 tableaux. La raison pour laquelle c'est 2^32 - 2 est - ce que cela fait de la plus grande valeur d'indice une valeur inférieure à 2^32 - 1 , qui est la valeur maximale que peut avoir un tableau
length
. (Par exemple, la longueur d'un tableau correspond à un entier non signé de 32 bits.) (Accessoires pour RobG de remarquer dans un commentaire sur mon blog que mon test précédent n'était pas tout à fait droit.)
C'est un tout petit peu d'itération aérienne ajoutée par boucle sur la plupart des tableaux, mais si vous avez un tableau clairsemé , il peut être un moyen plus efficace de boucle parce qu'il boucles uniquement pour les entrées qui existent réellement. Par exemple, pour le tableau ci - dessus, nous bouclons un total de trois fois (pour les touches "0"
, "10"
, et "10000"
- rappelez-vous, ce sont des cordes), pas 10,001 fois.
Maintenant, vous ne voudrez pas écrire que chaque fois, donc vous pourriez mettez ceci dans votre boîte à outils:
function arrayHasOwnIndex(array, prop) {
return array.hasOwnProperty(prop) && /^0$|^[1-9]\d*$/.test(prop) && prop <= 4294967294; // 2^32 - 2
}
et on l'utilise comme ça:
for (key in a) {
if (arrayHasOwnIndex(a, key)) {
console.log(a[key]);
}
}
ou si vous êtes intéressé par juste un test "assez bon pour la plupart des cas", vous pouvez utiliser ceci, mais pendant qu'il est proche, il n'est pas tout à fait correct:
for (key in a) {
// "Good enough" for most cases
if (String(parseInt(key, 10)) === key && a.hasOwnProperty(key)) {
console.log(a[key]);
}
}
4. Utiliser for-of
(utiliser un itérateur implicitement) (ES2015+)
ES2015 ajoute iterators à JavaScript. Le facile à utiliser des itérateurs est le nouveau for-of
. Il ressemble à ceci:
var val;
var a = ["a", "b", "c"];
for (val of a) {
console.log(val);
}
sortie:
a b c
sous les couvertures, qui obtient un iterator du tableau et les boucles à travers elle, obtenant les valeurs de lui. Cela n'a pas le problème que l'utilisation de for-in
a, parce qu'il utilise un itérateur défini par l'objet (le tableau), et les tableaux définissent que leurs itérateurs itèrent par leurs entrées (pas leurs propriétés). Contrairement à for-in
dans ES5, l'ordre dans lequel les entrées sont visitées est l'ordre numérique de leurs index.
5. Utiliser un itérateur explicitement (ES2015+)
Parfois, vous pourriez vouloir utiliser un itérateur explicitement . Vous pouvez le faire, aussi, bien que ce soit beaucoup plus clunk que for-of
. Il ressemble à ceci:
var a = ["a", "b", "c"];
var it = a.values();
var entry;
while (!(entry = it.next()).done) {
console.log(entry.value);
}
L'itérateur est un objet correspondant à l'Itérateur définition dans la spécification. Sa méthode next
renvoie un nouveau 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 pour cette itération. ( done
est facultatif si il serait false
, value
est facultatif si il serait undefined
.)
La signification de value
varie selon l'itérateur; les tableaux supportent (au moins) trois fonctions qui renvoient des itérateurs:
-
values()
: C'est celui que j'ai utilisé ci-dessus. Il renvoie un itérateur où chaquevalue
est l'entrée du tableau pour cette itération ("a"
,"b"
, et"c"
dans l'exemple précédent). -
keys()
: renvoie un itérateur où chaquevalue
est la clé pour que itération (donc pour notrea
ci-dessus, ce serait"0"
, puis"1"
, puis"2"
). -
entries()
: renvoie un itérateur où chaquevalue
est un tableau sous la forme[key, value]
pour cette itération.
Pour Tableau D'Objets Ressemblant À Des
outre les tableaux vrais, il y a aussi comme tableau objets qui ont une propriété length
et propriétés avec des noms numériques: NodeList
instances, l'objet arguments
, etc. Comment faire la boucle par le biais de leur contenu?
utilisez l'une des options ci-dessus pour les tableaux
au moins une partie, et peut-être la plupart ou même la totalité, des approches array ci-dessus s'appliquent aussi bien aux objets de type array:
-
Utiliser
forEach
et connexes (ES5+)les diverses 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
sur une propriétéNode
'schildNodes
. Vous souhaitez faire ceci:Array.prototype.forEach.call(node.childNodes, function(child) { // Do something with `child` });
si vous allez faire cela beaucoup, vous pourriez vouloir saisir une copie de la référence de la fonction dans une variable pour réutilisation, 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 simple
for
boucleévidemment, une simple boucle
for
s'applique aux objets de type tableau. -
utilisation
for-in
correctementfor-in
avec les mêmes garanties qu'avec un tableau devrait fonctionner avec des objets de type tableau aussi bien; 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
utilisera l'itérateur fourni par le objet (s'il y a lieu); nous allons voir comment cela se joue avec les différents objets de type tableau, en particulier ceux fournis par l'hôte. Par exemple, la spécification pour leNodeList
dequerySelectorAll
a été mise à jour pour supporter l'itération. La spécification pour leHTMLCollection
degetElementsByTagName
n'était pas. -
utiliser un itérateur explicitement (ES2015+)
Voir #4, nous allons voir comment les itérateurs jouer hors.
Créer un véritable tableau
d'Autres fois, vous pouvez convertir un tableau comme objet dans un vrai tableau. Cela est étonnamment facile:
-
utiliser la
slice
méthode des matricesnous pouvons utiliser la méthode
slice
des tableaux, qui comme les autres méthodes mentionné ci-dessus est "intentionnellement générique" et peut donc être utilisé avec des objets de type tableau, comme ceci:var trueArray = Array.prototype.slice.call(arrayLikeObject);
Ainsi, par exemple, si on veut convertir un
NodeList
en un véritable tableau, nous pourrions 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 plus tôt, qui ne vous permettent pas d'utiliser des objets fournis par l'hôte comme
this
comme ça. -
Utiliser étendre la syntaxe (
...
)il est également possible D'utiliser la "syntaxe de diffusion D'ES2015 avec des moteurs JavaScript supportant cette fonctionnalité:
var trueArray = [...iterableObject];
ainsi, par exemple, si nous voulons convertir un
NodeList
en un tableau vrai, avec une syntaxe spread cela devient très succinct:var divs = [...document.querySelectorAll("div")];
-
utilisation
Array.from
(spec) / (MDN)Array.from
(ES2015+, but easily polyfilled) crée un tableau à partir d'un objet similaire à un tableau, en passant optionnellement les entrées par une fonction de cartographie en premier. So:var divs = Array.from(document.querySelectorAll("div"));
ou si vous voulez obtenir un tableau des noms d'étiquette du éléments avec une classe donnée, vous utiliseriez la fonction de mapping:
// 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; });
mise en garde pour l'hôte objets fournis
si vous utilisez les fonctions Array.prototype
avec les fonctions fourni par l'hôte objets de type tableau (listes DOM et autres choses fournies par le navigateur plutôt que le moteur JavaScript), vous devez être sûr de tester dans vos environnements cibles pour s'assurer que l'objet fourni par l'hôte se comporte correctement. la Plupart ne se comportent correctement (maintenant), mais il est important de tester. La raison en est que la plupart des méthodes Array.prototype
que vous êtes susceptible de vouloir utiliser s'appuient sur l'objet fourni par l'hôte donnant une réponse honnête à l'abstrait [[HasProperty]]
opération. Au moment d'écrire ces lignes, les navigateurs font un très bon travail, mais la spécification 5.1 a tenu compte de la possibilité qu'un objet fourni par l'hôte ne soit pas honnête. C'est dans §8.6.2 , plusieurs paragraphes au-dessous de la grande table près du début de cette section), où il est dit:
les objets hôtes peuvent mettre en œuvre ces méthodes internes de n'importe quelle manière sauf indication contraire; par exemple, une possibilité est que
[[Get]]
et[[Put]]
pour un objet hôte particulier vont effectivement chercher et stockent des valeurs de propriété mais[[HasProperty]]
génère toujours false .
(Je n'ai pas pu trouver le verbiage équivalent dans la spécification ES2015, mais ce sera toujours le cas.) Encore une fois, à partir de cette Écriture les objets communs de type tableau fournis par l'hôte dans les navigateurs modernes [ NodeList
instances, par exemple] do handle [[HasProperty]]
correctement, mais il est important de tester.)
Edit : cette réponse est désespérément dépassée. Pour une approche plus moderne, regardez les méthodes disponibles sur un tableau . Les méthodes d'intérêt pourraient être:
- forEach
- carte
- filtre
- zip
- réduire
- tous "les 1519130920"
- certains
la façon standard d'itérer un tableau dans JavaScript est une vanille for
- boucle:
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 est que si vous avez un tableau dense, et chaque indice est occupée par un élément. Si le tableau est clairsemé, alors vous pouvez courir dans des problèmes de performance avec cette approche, puisque vous itérate sur un grand nombre d'indices qui n'existent pas vraiment tableau. Dans ce cas, une boucle for .. in
pourrait être une meilleure idée. cependant , vous devez utiliser les sauvegardes appropriées pour vous assurer que seules les propriétés désirées du tableau (c'est-à-dire les éléments du tableau) sont traitées, puisque la boucle for..in
sera également énumérée dans les navigateurs traditionnels, ou si les propriétés supplémentaires sont définies comme enumerable
.
Dans ECMAScript 5 il y aura un forEach méthode de la matrice prototype, mais il n'est pas pris en charge dans les navigateurs. Donc, pour pouvoir l'utiliser de façon cohérente, vous devez avoir un environnement qui le supporte (par exemple, noeud.js server side JavaScript), ou d'utiliser un "Polyfill". Le Polyfill pour cette fonctionnalité est, cependant, trivial et comme il rend le code plus facile à lire, il est un bon polyfill à inclure.
si vous utilisez la bibliothèque jQuery , vous pouvez utiliser jQuery.chaque :
$.each(yourArray, function(index, value) {
// do your stuff here
});
EDIT :
comme par question, l'utilisateur veut code en javascript au lieu de jquery donc l'édition est
var length = yourArray.length;
for (var i = 0; i < length; i++) {
// Do something with yourArray[i].
}
boucle arrière
je pense que le inverse pour loop mérite une mention ici:
for (var i = array.length; i--; ) {
// process array[i]
}
avantages:
- vous n'avez pas besoin de déclarer une variable temporaire
len
, ou comparer avecarray.length
sur chaque itération, l'une ou l'autre pouvant être une optimisation minute. - retrait des frères et sœurs du DOM in l'ordre inversé est généralement plus efficace . (Le navigateur doit faire moins de déplacement d'éléments dans ses tableaux internes.)
- si vous modifiez le tableau pendant la boucle, à l'index ou après i (par exemple vous supprimez ou insérez un élément à
array[i]
), alors une boucle avant sauterait l'élément qui s'est déplacé à gauche dans la position i , ou retransformer le i e point qui a été décalé à droite. Dans un traditionnel pour la boucle, vous pourrait mise à jour i pour pointer à l'article suivant qui nécessite le traitement - 1, mais simplement inverser le sens de l'itération est souvent un plus simple et solution plus élégante . - de même, lors de la modification ou de la suppression imbriqué éléments DOM, traitement à l'inverse peut contourner "erreurs de 1519440920" . Par exemple, envisagez de modifier l'innerHTML d'un noeud parent avant de manipuler ses enfants. Au moment où le nœud enfant est atteint, il sera détaché du DOM, ayant été remplacé par un enfant nouvellement créé lorsque l'innerHTML du parent a été écrit.
- il est plus court à taper, et lire , que certaines des autres options disponibles. Bien qu'il perde à
forEach()
et à ES6for ... of
.
désavantages:
- il traite les articles dans l'ordre inverse. Si vous construisiez un nouveau tableau à partir des résultats, ou imprimiez des choses à l'écran, naturellement la sortie sera inversée par rapport à l'ordre original.
- insérant à plusieurs reprises des frères et sœurs dans le DOM comme premier enfant afin de conserver leur ordre est moins efficace . (Le navigateur devra toujours changer les choses.) Pour créer des noeuds DOM de manière efficace et dans l'ordre, il suffit de boucler en avant et d'ajouter comme normal (et aussi utiliser un "fragment de document").
- La boucle de retournement est confusion pour les développeurs juniors. (Vous pouvez considérer qu'un avantage, selon votre perspective.)
dois-je toujours l'utiliser?
certains développeurs utilisent l'inverse pour boucle par défaut , à moins qu'il n'y ait une bonne raison de boucle vers l'avant.
bien que les gains de performance soient généralement insignifiants, il genre de cris:
"Tout le faire pour chaque élément de la liste, je ne se soucient pas de l'ordre!"
cependant dans la pratique qui est pas en fait un fiable indication de l'intention, car il est impossible de distinguer de ces occasions où vous faire se soucient de l'ordre, et vraiment faire besoin de boucle en sens inverse. Donc, en fait, une autre construction serait nécessaire pour exprimer avec précision l'intention "je m'en fous", quelque chose qui n'est pas disponible 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 efficacité est une préoccupation (dans la boucle la plus interne d'un jeu ou d'un moteur d'animation), alors il peut être acceptable d'utiliser l'inverse pour boucle comme votre go-to pattern. Il suffit de se rappeler que voir un reverse for loop dans le code existant ne signifie pas nécessairement que l'ordre non pertinent!
il est préférable d'utiliser forEach ()
en général pour le code de niveau supérieur où la clarté et la sécurité sont plus grandes préoccupations, je vous conseille d'utiliser Array::forEach
comme modèle par défaut:
- Il est clair à lire.
- indique que i ne va pas être décalé à l'intérieur du bloc (ce qui est toujours une surprise possible se cacher dans de longues
for
etwhile
boucles.) - il vous donne un champ libre pour fermeture.
- il réduit la fuite de variables locales et la collision accidentelle avec (et la mutation de) variables externes.
alors quand vous voyez l'inverse pour 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). De plus, le fait de voir une boucle traditionnelle vers l'avant peut indiquer que le déplacement peut avoir lieu.
(si la discussion de l'intention n'a pas de sens pour vous, alors vous et votre code pouvez bénéficier de regarder la conférence de Crockford sur le Style de programmation et votre cerveau .)
comment ça marche?
for (var i = 0; i < array.length; i++) { ... } // Forwards
for (var i = array.length; i--; ) { ... } // Reverse
vous remarquerez que i--
est la clause du milieu (où nous voyons habituellement une comparaison) et la dernière clause est vide (où nous voyons habituellement i++
). Cela signifie que i--
est également utilisé comme la condition pour la suite. De manière cruciale, il est exécuté et vérifié avant à chaque itération.
-
Comment peut-il commencer à
array.length
sans exploser?parce que
i--
exécute avant chaque itération, sur la première itération nous serons effectivement accéder à l'élément àarray.length - 1
qui évite tout problème avecTableau-hors-limitesundefined
. -
pourquoi ne cesse-t-il pas d'itérer avant index 0?
la boucle cessera d'être itérée lorsque la condition
i--
sera évaluée à une valeur de falsey (lorsqu'elle produira 0).l'astuce est que, contrairement à
--i
, la suitei--
l'opérateur décrètei
mais donne la valeur avant le décret. Votre console peut le démontrer:> var i = 5; [i, i--, i];
[5, 5, 4]
ainsi, sur la dernière itération, i était auparavant 1 et l'expression
i--
le change en 0 mais donne réellement 1 (vrai), et ainsi la condition passe. Sur la prochaine itérationi--
modifications je à -1 mais les rendements 0 (falsey), provoquant l'exécution immédiatement abandonner la partie inférieure de la boucle.dans les forwards traditionnels pour boucle,
i++
et++i
sont interchangeables (comme le souligne Douglas Crockford). Cependant dans l'inverse pour boucle, parce que notre décrément est aussi notre expression de condition, nous devons nous en tenir ài--
si nous voulons traiter l'élément à l'indice 0.
1519380920"
certaines personnes aiment dessiner une petite flèche dans l'inverse" boucle 1519100920", et se termine par un clin d'oeil:
for (var i = array.length; i --> 0 ;) {
les remerciements vont à WYL pour m'avoir montré les avantages et les horreurs de l'inverse pour loop.
Certains C style d'utilisation des langues foreach
à boucle à travers des énumérations. En JavaScript ceci est fait avec le for..in
structure de boucle :
var index,
value;
for (index in obj) {
value = obj[index];
}
il y a une prise. for..in
fera une boucle à travers chacun des membres dénombrables de l'objet, et les membres sur son prototype. Pour éviter de lire des valeurs héritées par le prototype de l'objet, il suffit de vérifier si la propriété appartient à la objet:
for (i in obj) {
if (obj.hasOwnProperty(i)) {
//do stuff
}
}
en outre, ECMAScript 5 a ajouté un forEach
méthode à Array.prototype
qui peut être utilisé pour énumérer sur un tableau en utilisant un calback (le polyfill est dans le docs donc vous pouvez toujours l'utiliser pour les navigateurs plus anciens):
arr.forEach(function (val, index, theArray) {
//do stuff
});
il est important de noter que Array.prototype.forEach
ne se casse pas lorsque le rappel renvoie false
. jQuery et trait de Soulignement.js fournissent leurs propres variations sur each
pour fournir des boucles qui peuvent être court-circuitées.
si vous voulez boucler un tableau, utilisez la boucle standard en trois parties for
.
for (var i = 0; i < myArray.length; i++) {
var arrayItem = myArray[i];
}
vous pouvez obtenir des optimisations de performance en cache myArray.length
ou en itérant sur elle à l'envers.
Un forEach mise en œuvre ( 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
}
);
si cela ne vous dérange pas de vider le tableau:
var x;
while(x = y.pop()){
alert(x); //do something
}
x
contiendra la dernière valeur de y
et il sera retiré du tableau. Vous pouvez également utiliser shift()
qui donnera et supprimer le premier élément de y
.
je sais que c'est un vieux poste, et il y a tellement de grandes réponses déjà. Pour être un peu plus complet, j'ai pensé en rajouter un autre en utilisant AngularJS . Bien sûr, cela ne s'applique que si vous utilisez L'angle, évidemment, néanmoins je voudrais le dire de toute façon.
angular.forEach
prend 2 arguments et un troisième argument optionnel. Le premier argument est l'objet (array) pour itérer sur, le deuxième argument est l'itérateur fonction, et le troisième argument optionnel est le contexte de l'objet (essentiellement désigné à l'intérieur de la boucle comme "ceci".
Il y a différentes façons d'utiliser la boucle forEach angulaire. 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 façon qui est utile pour copier des éléments d'un tableau à 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);
cependant, vous ne devez pas faire cela, vous pouvez simplement faire ce qui suit et il est équivalent à la exemple précédent:
angular.forEach(temp, function(item) {
temp2.push(item);
});
maintenant, il y a des avantages et des inconvénients de l'utilisation de la fonction angular.forEach
par opposition à la boucle for
à saveur de vanille.
Pros
- lisibilité facile
- facilité d'écriture
- si disponible,
angular.forEach
utilisera la boucle ES5 forEach. Maintenant, je vais passer à l'efficience dans la section cons, comme les boucles forEach sont beaucoup plus lent que les boucles for. Je le mentionne en tant que pro parce que 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 chaque objet contient un tableau de résultats, dont chacun a une propriété de valeur qui est une chaîne (ou autre). Et disons que nous devons itérer sur chacun des résultats et si ils sont égaux alors Effectuer une certaine 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
}
}
}
accordé c'est un exemple hypothétique très simple, mais j'ai écrit triple embedded pour les boucles en utilisant la deuxième approche et il était très difficile à lire, et écrire pour cette matière.
Cons
- efficacité.
angular.forEach
, et le natifforEach
, d'ailleurs, sont tous les deux ainsi beaucoup plus lent que la boucle normalefor
....environ 90% plus lent . Ainsi, pour les grands ensembles de données, Mieux vaut s'en tenir à la bouclefor
native. - Pas de pause, continuer, ou de l'aide au retour.
continue
est en fait soutenu par " accident ", pour continuer dans unangular.forEach
vous avez simplement mis unreturn;
déclaration dans la fonction commeangular.forEach(array, function(item) { if (someConditionIsTrue) return; });
qui la fera continuer hors de la fonction pour cette itération. Cela est également dû au fait que le natifforEach
ne supporte pas break ou continuer non plus.
je suis sûr qu'il y a d'autres avantages et inconvénients, et s'il vous plaît n'hésitez pas à ajouter ceux que vous jugez bon. Je pense que, en fin de compte, si vous avez besoin d'efficacité, restez avec juste la boucle for
natif pour vos besoins de bouclage. Mais, si vos ensembles de données sont plus petits et une certaine efficacité est acceptable d'abandonner en échange de lisibilité et ecrivabilité, puis par tous les moyens jeter un angular.forEach
dans ce mauvais garçon.
une solution facile serait maintenant d'utiliser le soulignement .bibliothèque js . Il fournit de nombreux outils utiles, tels que each
et déléguera automatiquement le travail au natif forEach
si disponible.
un exemple de code de la façon dont il fonctionne est:
var arr = ["elemA", "elemB", "elemC"];
_.each(arr, function(elem, index, ar)
{
...
});
voir aussi
- "1519180920 à la Documentation" natif
Array.prototype.forEach()
. - Dans for_each... (MDN), il est expliqué que
for each (variable in object)
est obsolète, puisque la partie de l'ECMA-357 ( EAX ) standard. - ...de (MDN) décrit la prochaine façon d'itérer en utilisant
for (variable of object)
comme partie de la proposition Harmony (ECMAScript 6).
probablement la boucle for(i = 0; i < array.length; i++)
n'est 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]
. Tout d'abord, cela fera référence à des variables que vous n'avez même pas, ensuite 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 retourne:
//Hello
//World
//!!!
il y a trois implémentations de foreach
dans 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
de ES6:
list = [0, 1, 2, 3]
for (let obj of list) {
console.log(obj)
}
où of
évite les bizarreries associées à in
et le fait fonctionner comme la boucle for
de toute autre langue, et let
se lie i
dans la boucle par opposition à dans la fonction.
Les accolades ( {}
) peut être omis lorsqu'il n'y a qu'une seule commande (par exemple dans l'exemple ci-dessus).
il n'y a pas de for each
boucle en natif JavaScript . Vous pouvez utiliser les bibliothèques pour obtenir cette fonctionnalité (je recommande Underscore.js ), utilisez un simple for
en boucle.
for (var instance in objects) {
...
}
cependant, notez qu'il peut y avoir des raisons d'utiliser une boucle encore plus simple for
(voir la question sur le débordement de la pile Pourquoi utiliser "for...in" avec l'itération du tableau est une si mauvaise idée? )
var instance;
for (var i=0; i < objects.length; i++) {
var instance = objects[i];
...
}
il s'agit d'un itérateur pour la liste NON-sparse où l'index commence à 0, ce qui est le scénario typique lorsqu'il s'agit de document.getelemensbytagname 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 étiquette p obtient class="blue"
exemple #3
each.call(document.getElementsByTagName('p'),
"if( i % 2 == 0) this.className = data;",
'red'
);
chaque autre étiquette p obtient class="red"
>
exemple #4
each.call(document.querySelectorAll('p.blue'),
function(newClass, i) {
if( i < 20 )
this.className = newClass;
}, 'green'
);
et finalement les 20 premières étiquettes bleues p sont changées en vert
attention lors de l'utilisation de la chaîne comme fonction: la fonction est créée hors contexte et ne doit être utilisée que si vous êtes certain de la portée de la variable. Autrement, mieux passer des fonctions où scoping est plus intuitif.
Il y a peu de moyens pour parcourir un tableau en JavaScript, comme ci-dessous:
pour - c'est le plus commun. Bloc complet de code pour boucle
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>
tandis que - boucle pendant qu'une condition est terminée. Il 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 alors que la condition est vraie, sera exécuté 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>
functional loops - forEach
, map
, filter
, aussi reduce
(ils boucle à travers la fonction, mais utilisé 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 des exemples de programmation fonctionnelle sur les tableaux, consultez le blog programmation fonctionnelle en JavaScript: carte, filtre et réduit .
il n'y a pas de capacité intégrée pour entrer dans forEach
. Pour interrompre l'exécution, utilisez le Array#some
comme ci-dessous:
[1,2,3].some(function(number) {
return number === 1;
});
cela fonctionne parce que some
retourne true dès que l'un des callbacks, exécuté dans l'ordre du tableau, retourne true, court-circuitant l'exécution du reste.
Réponse Originale
voir prototype de tableau pour certains
ECMAScript5 (la version en Javascript) pour travailler avec des tableaux.
forEach - itère à travers chaque élément dans le tableau et faire tout ce dont vous avez besoin avec chaque élément.
['C', 'D', 'E'].forEach(function(element, index) {
console.log(element + " is the #" + (index+1) + " in 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é sur le fonctionnement sur le tableau en utilisant une certaine fonctionnalité intégrée.
carte - Il crée un nouveau tableau avec le résultat de la fonction de rappel. Cette méthode est bonne à utiliser 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']
reduce - comme le nom le dit, il réduit le tableau à une seule valeur en appelant la fonction donnée passant dans l'élément currenct 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 - retourne true ou false si tous les éléments du tableau passent 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
filtre - très similaire à tous sauf que le filtre renvoie un tableau avec les éléments qui reviennent vrais à 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]
espérons que ce sera utile.
je voudrais également ajouter ce que une composition d'une boucle de retournement et une réponse ci-dessus pour quelqu'un qui voudrait de cette syntaxe.
var foo = [object,object,object];
for (var i = foo.length, item; item = foo[--i];) {
console.log(item);
}
Pour:
l'avantage pour ceci: vous avez la référence déjà dans le premier comme cela ne devra pas être déclaré plus tard avec une autre ligne. Il est pratique lors de la boucle à travers le tableau d'objets.
Inconvénients:
cela se casse chaque fois que la référence est false - falsey (Non défini, etc.). Il peut être utilisé comme un avantage. Cependant, il serait un peu plus difficile à lire. Et aussi selon le navigateur, il peut être" pas " optimisé pour travailler plus vite que l'original.
jQuery façon à l'aide de $.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];
d'Une façon plus proche de votre idée serait d'utiliser Array.forEach()
qui accepte un clojure fonction 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()
qui fonctionne de la même manière mais aussi mutates
chaque élément et le renvoie comme:
var myArray = [1, 2, 3];
myArray = myArray.map(
(item) => {
return item + 1;
}
);
console.log(myArray); // [2, 3, 4]
la syntaxe lambda ne fonctionne habituellement pas dans IE 10 ou en dessous.
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);
});
If you are a jQuery Fan and already have a jQuery file running, you should reverse the positions of the index and value parameters
$("#ul>li").each(function(**index,value**){
console.log("value of the looped element" + value);
console.log("index of the looped element" + index);
});
var a = ["car", "bus", "truck"]
a.forEach(function(item, index) {
console.log("Index" + index);
console.log("Element" + item);
})
vous pouvez appeler forEach comme ceci:
let Array = [1,3,2];
theArray.forEach((element)=>{
// use the element of the array
console.log(element)
}
élément aura la valeur de chaque indice de 0 à la longueur du tableau.
sortie:
1
3
2
explication:
forEach est en classe prototype. vous pouvez aussi l'appeler theArray.prototype.forEach(...);
prototype: https://hackernoon.com/prototypes-in-javascript-5bba2990e04b
vous pouvez également modifier sur un tableau comme ceci:
for(let i=0;i<theArray.length;i++){
console.log(i); //i will have the value of each index
}
Si vous voulez utiliser forEach()
, il ressemblera -
theArray.forEach ( element => {
console.log(element);
});
Si vous voulez utiliser for()
, il ressemblera -
for(let idx = 0; idx < theArray.length; idx++){
let element = theArray[idx];
console.log(element);
}
si vous avez un tableau massif que vous devriez utiliser iterators
pour gagner en efficacité. Les itérateurs sont une propriété de certaines collections JavaScript (comme Map
, Set
, String
, Array
). Même, for..of
emplois iterator
sous le capot.
améliorent l'efficacité en vous permettant de consommer les articles d'une liste un par un comme s'ils étaient un flux. Ce qui rend un iterator spécial, c'est la façon dont il traverse une collection. D'autres boucles ont besoin de charger la totalité de la collection à l'avance pour itérer dessus, alors qu'un itérateur n'a besoin de connaître que la position actuelle dans la collection.
vous accédez à l'élément courant en appelant l'itérateur next
la méthode. La méthode suivante retournera le value
de l'article courant et un boolean
pour indiquer quand vous avez atteint la fin de la collection. Ce qui suit est un exemple de création d'un itérateur à partir d'un tableau.
Transformez votre tableau régulier en itérateur en utilisant 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 aussi transformer votre tableau régulier en itérateur en utilisant Symbol.iterator
comme 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 aussi transformer votre régulier array
en un iterator
comme ceci:
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}
NOTE :
- les itérateurs sont de nature épuisable.
- les Objets ne sont pas
iterable
par défaut. Utilisezfor..in
dans ce cas car au lieu de VALEURs il fonctionne avec des clés.
vous pouvez en savoir plus sur iteration protocol
ici .
résumé:
lorsque nous itérons sur un tableau, nous pouvons souvent vouloir accomplir l'un des buts suivants:
-
nous voulons itérer sur le tableau et créer un nouveau tableau:
Array.prototype.map
-
Nous voulons parcourir le tableau et ne pas créer un nouveau tableau:
Array.prototype.forEach
for..of
boucle
dans JS il y a plusieurs façons d'atteindre ces deux objectifs. Toutefois, certains sont plus conventionnels que d'autres. Ci-dessous, vous pouvez trouver quelques méthodes couramment utilisées (la plus conventionnelle imo) pour accomplir l'itération du tableau en javascript.
création d'un nouveau tableau: Map
map()
est une fonction située sur Array.prototype
qui peut transformer chaque élément d'un tableau et retourne ensuite un nouveau tableau. map()
prend comme argument une fonction de rappel et fonctionne de la façon 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 callback que nous avons passé dans map()
comme argument est exécuté pour chaque élément. Ensuite, un tableau revient qui a la même longueur que le tableau d'origine. Dans ce nouveau tableau, l'élément est transformé par la fonction callback passée en argument à map()
.
la différence nette entre map
et un autre mécanisme de boucle comme forEach
et une for..of
boucle sont que map
retourne comme nouveau tableau et laisse le vieux tableau intact (sauf si vous le manipulez explicitement avec pense comme splice
).
également noter que le callback de la fonction map
fournit comme second argument le numéro d'index de l'itération courante. De plus, le troisième argument fournit-il le tableau sur lequel map
a été appelé. Parfois, ces propriétés peuvent être très utiles.
Boucle utilisant forEach
forEach
est une fonction située sur Array.prototype
qui prend une fonction de rappel comme argument. Il exécute alors cette fonction de rappel pour chaque élément dans le tableau. Contrairement à la fonction map()
, 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 fonction map
, le forEach
callback fournit comme second argument le numéro d'index de l'itération courante. Le troisième argument fournit également le tableau sur lequel forEach
a été appelé.
boucle à travers des éléments en utilisant for..of
les boucles de boucle for..of
à travers chaque élément d'un tableau (ou tout autre objet itérable). Il 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 element
signifie un élément de tableau et arr
est le tableau que nous voulons boucle. Non pas que le nom element
soit arbitraire et nous aurions pu choisir n'importe quel autre nom comme " el " ou quelque chose de plus déclaratif quand c'est le cas.
ne confondez pas la boucle for..in
avec la boucle for..of
. for..in
fera une boucle à travers toutes les propriétés énumérables du tableau alors que la boucle for..of
ne fera qu'une boucle à travers 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);
}
function printList(callback) {
// do your printList work
console.log('printList is done');
callback();
}
function updateDB(callback) {
// do your updateDB work
console.log('updateDB is done');
callback()
}
function getDistanceWithLatLong(callback) {
// do your getDistanceWithLatLong work
console.log('getDistanceWithLatLong is done');
callback();
}
function runSearchInOrder(callback) {
getDistanceWithLatLong(function() {
updateDB(function() {
printList(callback);
});
});
}
runSearchInOrder(function(){console.log('finished')});
sortie getDistanceWithLatLong est fait updateb est fait printList est fait fini