Antwort an „Felix Riesterer“ verfassen

Lieber Rolf,

aber ich glaube trotzdem, dass Dir hier ein Irrtum rausgerutscht ist und Du Closure mit Scope verwechselst.

das kann grundsätzlich immer passieren, aber hier ging es mir nur um die Möglichkeit, Closures nutzen zu können. Dass im vorliegenden Fall keine Closure vorkommt, ist mir natürlich klar gewesen. Es gibt aber Fälle, bei denen man innerhalb einer Schleife gewisse Dinge nicht so einfach tun kann, weil es in einer Schleife selbst keine Closures gibt, was am prozeduralen Kontext liegt. Ein besseres Szenario bietet mein Tutorial zum Umgang mit Callback-Funktionen, darin das Kapitel Callback-Funktionen als Kapselungen.

  • .forEach muss pro Durchlauf eine Callbackfunktion aufrufen. Für for...of muss hingegen ein Iteratorobjekt erzeugt und dieser Iterator durchlaufen werden. Der Performanceunterschied dürfte sich im Nanosekundenbereich bewegen, ich habe es nicht gemessen.

Irgendwo habe ich mal gelesen, dass Funktionsaufrufe gut parallelisierbar wären, weshalb der funktionale Stil auf Mehrkernsystemen bessere Leistung brächte. Aber das ist mir völlig egal, mir geht es um den Schreibstil, der für mich persönlich überschaubarer ist.

  • .forEach benötigt voneinander entfernte Klammerpaare, die balanciert bleiben müssen. Die for...of-Schleife hat dagegen die runden Klammern beieinander und nur die geschweiften Klammern sind voneinander entfernt.

Syntax muss stimmen. Immer. Das sehe ich weder als Vor-, noch als Nachteil. Die Klammern um die Geschichte herum müssen halt passen. Aber die Variablen in der Funktion funktionieren nun einmal etwas anders, als in einer Schleife.

  • .forEach liefert außer dem Schleifenwert auch den aktuellen Schleifenindex und das iterierte Objekt als weitere Parameter. Wenn man das braucht, hat .forEach Vorteile. Braucht man es nicht, ist es unnötiger Overhead.

Den merke ich aber nicht, wenn ich in der Callback-Funktion nur ein Argument entgegen nehme, denn der Index ist ein zweites Argument, das ich auch ignorieren kann. Stört also nicht.

  • Dadurch, dass .forEach den Schleifenrumpf als Funktion erwartet, kann man den Rumpf einmal programmieren und für mehrere Schleifen wiederverwenden. Aus meiner Sicht wenig nützlich und ggf. sogar verwirrend. Rumpf und Schleife gehören normalerweise zusammen. Heißt: wenn ich den Schleifenrumpf wiederverwenden will, kann ich auch das for...of mit in die Funktion schieben und die zu durchlaufende Kollektion als Argument übergeben.

In der Praxis verwende ich anonyme Callback-Funktionen, weil die Verarbeitung der Elemente einer Liste fast immer individuell ist, sodass ich auch eine individuell gestaltete Callback-Funktion benötige. Nur selten definiere ich diese eigenständig, um sie dann über ihren Namen im forEach-Aufruf zu referenzieren.

  • .forEach ist funktional und for...of ist prozedural. Ob das vor- oder nachteilig ist, ist eine Sache des persönlichen Geschmacks und des Stils, in dem die gesamte Anwendung erstellt wird.

Und genau hier tendiert mein persönlicher Geschmack sehr stark zur funktionalen Schreibweise. Ich mache mir einfach keine Gedanken mehr darüber, welche Art der for-Schleife ich benötige:

for (let i = 0; i < myArray.length; i++) { myArray[i] = false; }
myArray.forEach(element => element = false);

for (myProperty in myObject) { myObject[myProperty] = false; }
Object.keys(myObject).forEach(myProperty => myObject[myProperty] = false);

for (myValue of myObject) { console.log(myValue); }
Object.values(myObject).forEach(myValue => console.log(myValue));

Zugegeben, im letzten Fall würde ich mir einen Wolf schreiben. Aber für mich ist es gedanklich die immer gleiche Art, über eine Liste zu iterieren, egal ob es jetzt Elemente in einem Array sind, Elemente in einer NodeList, oder Eigenschaften eines Objekts. Im Zweifel erzeuge ich mir mit Array.from() ein Array, um forEach zur Verfügung zu haben:

Array.from(node.getElementsByTagName("p")).forEach(p => {
  // tu was mit p
});

Deswegen finde ich for...of für iterierbare Kollektionen heute die bessere Lösung. Die .forEach-Methode hat Nutzen, wenn eine Kollektion keinen Iterator hat, oder wenn ich die zusätzlichen Parameter des .forEach-Callbacks brauche.

Für mich hat sie den Nutzen, dass ich auf die immer gleiche Weise vorgehen kann.

Liebe Grüße

Felix Riesterer

freiwillig, öffentlich sichtbar
freiwillig, öffentlich sichtbar
freiwillig, öffentlich sichtbar

Ihre Identität in einem Cookie zu speichern erlaubt es Ihnen, Ihre Beiträge zu editieren. Außerdem müssen Sie dann bei neuen Beiträgen nicht mehr die Felder Name, E-Mail und Homepage ausfüllen.

abbrechen