web-dev-qa-db-fra.com

JavaScript - Nuances de myArray.forEach vs for loop

J'ai vu beaucoup de questions suggérant d'utiliser:

for (var i = 0; i < myArray.length; i++){ /* ... */ }

au lieu de:

for (var i in myArray){ /* ... */ }

pour les tableaux, en raison d'une itération incohérente ( voir ici ).


Cependant, je n'arrive pas à trouver quoi que ce soit qui semble préférer la boucle orientée objet:

myArray.forEach(function(item, index){ /* ... */ });

Ce qui me semble beaucoup plus intuitif.

Pour mon projet actuel, la compatibilité IE8 est importante et je songe à utiliser polyfill de Mozilla , mais je ne suis pas sûr à 100% comment cela fonctionnera.

  • Existe-t-il des différences entre la norme pour la boucle (le premier exemple ci-dessus) et la mise en oeuvre de Array.prototype.forEach par les navigateurs modernes?
  • Existe-t-il une différence entre les implémentations de navigateur modernes et l'implémentation de Mozilla liée à ce qui précède (en ce qui concerne IE8)?
  • Les performances ne sont pas aussi un problème, mais simplement la cohérence avec laquelle les propriétés sont itérées.
88
Michael Lewis

La différence la plus importante entre la boucle for et la méthode forEach est que, avec la méthode précédente, vous pouvez break sortir de la boucle. Vous pouvez simuler continue en revenant simplement de la fonction passée à forEach, mais il n’ya aucun moyen d’arrêter complètement de faire une boucle.

En dehors de cela, les deux remplissent efficacement la même fonctionnalité. Une autre différence mineure concerne la portée de l'index (et toutes les variables contenant) dans la boucle for, en raison du levage variable.

// 'i' is scoped to the containing function
for (var i = 0; i < arr.length; i++) { ... }

// 'i' is scoped to the internal function
arr.forEach(function (el, i) { ... });

Cependant, j'estime que forEach est beaucoup plus expressif: il représente votre intention de parcourir chaque élément d'un tableau et vous fournit une référence à l'élément, pas seulement à l'index. Globalement, tout dépend de vos goûts personnels, mais si vous pouvez utiliser forEach, je vous recommanderais de l’utiliser.


Il existe quelques différences plus substantielles entre les deux versions, en particulier en ce qui concerne les performances. En fait, la boucle simple for fonctionne beaucoup mieux que la méthode forEach, comme le montre ce test jsperf .

Que ce soit ou non une telle performance est nécessaire pour vous, c'est à vous de décider, et dans la plupart des cas, je privilégierais l'expressivité à la vitesse. Cette différence de vitesse est probablement due aux différences sémantiques mineures entre la boucle de base et la méthode lors de l'utilisation de tableaux épars, comme indiqué dans cette réponse .

Si vous n'avez pas besoin du comportement de forEach et/ou vous avez besoin de sortir de la boucle plus tôt, vous pouvez utiliser le Lo-Dash _.each comme alternative, qui fonctionnera également sur plusieurs navigateurs. Si vous utilisez jQuery, il fournit également un $.each , notez simplement les différences dans les arguments passés à la fonction de rappel dans chaque variante.

(En ce qui concerne le forEach polyfill, il devrait fonctionner sans problème dans les navigateurs plus anciens, si vous choisissez d'aller dans cette voie.)

121
Alexis King

Vous pouvez utiliser votre fonction foreach personnalisée qui fonctionnera beaucoup mieux que Array.forEach

Vous devriez ajouter ceci une fois à votre code. Cela ajoutera une nouvelle fonction au tableau.

function foreach(fn) {
    var arr = this;
    var len = arr.length;
    for(var i=0; i<len; ++i) {
        fn(arr[i], i);
    }
}

Object.defineProperty(Array.prototype, 'customForEach', {
    enumerable: false,
    value: foreach
});

Ensuite, vous pouvez l’utiliser n’importe où, comme Array.forEach

[1,2,3].customForEach(function(val, i){

});

La seule différence est 3 fois plus rapide. https://jsperf.com/native-arr-foreach-vs-custom-foreach

UPDATE: Dans la nouvelle Chrome, les performances de .forEach () ont été améliorées. Toutefois, la solution peut améliorer les performances des autres navigateurs.

JSPerf

12
Seagull

De nombreux développeurs (par exemple Kyle Simpson) suggèrent d’utiliser .forEach pour indiquer que le tableau aura un effet secondaire et .map pour les fonctions pures. Les boucles for constituent une solution polyvalente pour un nombre connu de boucles ou pour tout autre cas qui ne convient pas car il est plus facile de communiquer en raison de son support étendu dans la plupart des langages de programmation.

par exemple.

/* For Loop known number of iterations */
const numberOfSeasons = 4;
for (let i = 0; i < numberOfSeasons; i++) {
  //Do Something
}

/* Pure transformation */
const arrayToBeUppercased = ['www', 'html', 'js', 'us'];
const acronyms = arrayToBeUppercased.map((el) => el.toUpperCase));

/* Impure, side-effects with .forEach */
const acronymsHolder = [];
['www', 'html', 'js', 'us'].forEach((el) => acronymsHolder.Push(el.toUpperCase()));

En ce qui concerne la convention, cela semble préférable, mais la communauté n’a pas encore défini de convention sur le nouveau protocole d’itération for in boucles. Généralement, je pense que c'est une bonne idée de suivre les concepts FP) que la communauté JS semble ouverte à adopter.

4
steviejay