JavaScript – Nuancen von myArray.forEach vs. for-Schleife

Lesezeit: 6 Minuten

Benutzer-Avatar
Michael Lewis

Ich habe viele Fragen gesehen, die vorschlagen, Folgendes zu verwenden:

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

Anstatt von:

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

für Arrays aufgrund inkonsistenter Iteration (siehe hier).


Ich kann jedoch nichts finden, was die objektorientierte Schleife zu bevorzugen scheint:

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

Was mir viel intuitiver erscheint.

Für mein aktuelles Projekt ist die IE8-Kompatibilität wichtig, und ich erwäge die Verwendung Polyfill von Mozillaaber ich bin mir nicht 100% sicher, wie das funktionieren wird.

  • Gibt es Unterschiede zwischen der standardmäßigen for-Schleife (das erste Beispiel oben) und der Array.prototype.forEach-Implementierung durch moderne Browser?
  • Gibt es einen Unterschied zwischen modernen Browserimplementierungen und der oben verlinkten Mozilla-Implementierung (insbesondere im Hinblick auf IE8)?
  • Die Leistung ist nicht so sehr ein Problem, sondern nur die Konsistenz, mit der Eigenschaften iteriert werden.

  • Es ist nicht möglich break aus forEach. Ein großer Vorteil ist jedoch, mit der Funktion einen neuen Geltungsbereich zu erstellen. Mit dem Polyfill solltest du keine Probleme haben (zumindest sind mir keine begegnet).

    – hgoebl

    12. Mai 2014 um 16:32 Uhr

  • Die Probleme, die Sie mit älteren IE haben können, ist nicht der Shim selbst, sondern der kaputte Array-Konstruktor/Literal wrt holes wo undefined sein sollte und andere kaputte Methoden, wie slice und hasOwnProperty wrt zu arrayartigen DOM-Objekten. Meine Prüfung u es5 shim haben gezeigt, dass solche Shim-Methoden mit der Spezifikation konform sind (MDN-Shim nicht getestet).

    – Xotic750

    12. Mai 2014 um 16:57 Uhr

  • Und bzgl. des Ausbruchs aus a for Schleife, das ist was some ist für.

    – Xotic750

    12. Mai 2014 um 16:59 Uhr

  • “Ich kann jedoch anscheinend nichts finden, was die objektorientierte Schleife zu bevorzugen scheint:” Ich würde es eher funktional als zwingend nennen.

    – Memke

    29. November 2016 um 10:16 Uhr


  • Sie können verwenden Array.find() aus der Schleife auszubrechen, nachdem Sie eine erste Übereinstimmung gefunden haben.

    – Mottie

    25. Dezember 2016 um 14:44 Uhr

Benutzer-Avatar
Alexis König

Der wesentlichste Unterschied zw for Schleife und die forEach Methode ist, dass Sie mit ersterem können break aus der Schleife. Sie können simulieren continue durch einfaches Zurückkehren von der Funktion, an die übergeben wurde forEachaber es gibt keine Möglichkeit, die Schleife ganz zu stoppen.

Abgesehen davon erfüllen die beiden praktisch die gleiche Funktionalität. Ein weiterer kleiner Unterschied betrifft den Gültigkeitsbereich des Indexes (und aller darin enthaltenen Variablen) in der for-Schleife aufgrund des Hebens von Variablen.

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

Allerdings finde ich das forEach ist viel aussagekräftiger – es stellt Ihre Absicht dar, jedes Element eines Arrays zu durchlaufen, und liefert Ihnen eine Referenz auf das Element, nicht nur auf den Index. Insgesamt kommt es hauptsächlich auf den persönlichen Geschmack an, aber wenn Sie es verwenden können forEachwürde ich empfehlen, es zu verwenden.


Es gibt einige weitere wesentliche Unterschiede zwischen den beiden Versionen, insbesondere in Bezug auf die Leistung. Tatsächlich schneidet die einfache for-Schleife erheblich besser ab als die forEach Methode, wie gezeigt durch dieser Jsperf-Test.

Ob eine solche Leistung für Sie notwendig ist oder nicht, müssen Sie selbst entscheiden, und in den meisten Fällen würde ich Ausdrucksstärke der Geschwindigkeit vorziehen. Dieser Geschwindigkeitsunterschied ist wahrscheinlich auf die geringfügigen semantischen Unterschiede zwischen der grundlegenden Schleife und der Methode zurückzuführen, wenn mit Arrays mit geringer Dichte gearbeitet wird, wie in dieser Antwort angegeben.

Wenn Sie das Verhalten von nicht benötigen forEach und/oder Sie früh aus der Schleife ausbrechen müssen, können Sie Lo-Dash’s verwenden _.each als Alternative, die auch browserübergreifend funktioniert. Wenn Sie jQuery verwenden, bietet es auch eine ähnliche $.eachbeachten Sie einfach die Unterschiede in den Argumenten, die in jeder Variante an die Callback-Funktion übergeben werden.

(Wie für die forEach polyfill, es sollte in älteren Browsern problemlos funktionieren, wenn Sie sich für diesen Weg entscheiden.)

  • Es ist erwähnenswert, dass die Bibliotheksversionen each verhalten sich nicht wie die ECMA5-Spezifikation von forEach, neigen sie dazu, alle Arrays als dicht zu behandeln (um IE-Bugs zu vermeiden, vorausgesetzt, Sie sind sich dessen bewusst). Kann sonst ein “Gotcha” sein. Als Referenz github.com/es-shims/es5-shim/issues/190

    – Xotic750

    12. Mai 2014 um 17:01 Uhr


  • Außerdem gibt es einige Prototypmethoden, mit denen Sie brechen können, z Array.prototype.some was eine Schleife durchläuft, bis Sie einen wahren Wert zurückgeben oder bis es das Array vollständig durchlaufen hat. Array.prototype.every ist ähnlich wie Array.prototype.some aber stoppt, wenn Sie einen falschen Wert zurückgeben.

    – axelduch

    12. Mai 2014 um 17:15 Uhr

  • Wenn Sie einige Testergebnisse auf verschiedenen Browsern und solchen Shims sehen möchten, können Sie hier einen Blick darauf werfen. ci.testling.com/Xotic750/util-x

    – Xotic750

    12. Mai 2014 um 17:16 Uhr

  • Außerdem würde die Verwendung von Array.prototype.forEach Ihren Code der Gnade der Erweiterung aussetzen. Wenn Sie beispielsweise einen Code schreiben, der in eine Seite eingebettet werden soll, besteht die Möglichkeit, dass Array.prototype.forEach mit etwas anderem überschrieben wird.

    – Marmordämon

    19. August 2016 um 4:32 Uhr


  • @MarbleDaemon Die Wahrscheinlichkeit dafür ist so gering, dass es praktisch unmöglich und daher vernachlässigbar ist. Überschreiben Array.prototype.forEach mit einer nicht kompatiblen Version hätte das Potenzial, so viele Bibliotheken zu beschädigen, dass es sowieso nicht helfen würde, sie aus diesem Grund zu vermeiden.

    – Alexis König

    19. August 2016 um 4:54 Uhr

Benutzer-Avatar
Möwe

Sie können Ihre benutzerdefinierte foreach-Funktion verwenden, die viel besser funktioniert als Array.forEach

Sie sollten dies einmal zu Ihrem Code hinzufügen. Dadurch wird dem Array eine neue Funktion hinzugefügt.

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

Dann können Sie es überall wie Array.forEach verwenden

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

});

Der einzige Unterschied ist 3 mal schneller. https://jsperf.com/native-arr-foreach-vs-custom-foreach

UPDATE: In der neuen Chrome-Version wurde die Leistung von .forEach() verbessert. Die Lösung kann jedoch die zusätzliche Leistung in anderen Browsern bereitstellen.

JSPerf

Benutzer-Avatar
steviesch

Es wird von vielen Entwicklern (z. B. Kyle Simpson) zur Verwendung vorgeschlagen .forEach um anzuzeigen, dass das Array eine Nebenwirkung haben wird und .map für reine Funktionen. for Schleifen eignen sich gut als Allzwecklösung für eine bekannte Anzahl von Schleifen oder jeden anderen Fall, der nicht passt, da es aufgrund seiner breiten Unterstützung in den meisten Programmiersprachen einfacher zu kommunizieren ist.

z.B

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

Konventionell scheint dies am besten zu sein, aber die Community hat sich nicht wirklich auf eine Konvention für das neuere Iterationsprotokoll geeinigt for in Schleifen. Im Allgemeinen denke ich, dass es eine gute Idee ist, den FP-Konzepten zu folgen, für die die JS-Community offen zu sein scheint.

1168750cookie-checkJavaScript – Nuancen von myArray.forEach vs. for-Schleife

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy