Bildauswahl Reset
bearbeitet von Rolf BWarnung an diejenigen, die keine Programmierstil-Enthusiasten sind: Haarspalterei voraus!
Hallo Felix,
ich habe großen Respekt vor deiner Kompetenz und Erfahrung, aber ich glaube trotzdem, dass Dir hier ein Irrtum rausgerutscht ist und Du Closure mit Scope verwechselst.
Allgemein entsteht eine Closure, wenn ein Funktionsobjekt erzeugt wird und der Code der Funktion auf Variablen zugreift, die außerhalb der Funktion deklariert wurden. Die Closure ist das Bündel, das diese Variablen „rettet“, falls das Funktionsobjekt seinen erzeugenden Scope überlebt. Wie das technisch abläuft, ist ein Implementierungsdetail und hier unwichtig. Aber eins ist wichtig: Die Parameter und lokalen Variablen der Funktion sind **nicht** Teil der Closure. Können sie auch nicht sein, denn die Variablen, die in der Closure enthalten sind, leben so lange weiter wie das Funktionsobjekt besteht. Die lokalen Variablen hingegen leben gerade so lange, wie ein Aufruf dieser Funktion dauert (es sei denn, natürlich, dass dieser Funktionsaufruf eine weitere Closure erzeugt…)
Im konkreten Fall besteht überhaupt kein Bedarf für eine Closure. Der Schleifenrumpf greift nur auf `gallery` zu, der bei mir die foreach-Laufvariable ist und bei Dir der Callback-Parameter. `banner` und `thumb1` sind lokal, und hier stimme ich Dir bei: const ist richtig, let war falsch.
Durch die Funktion sind `banner` und `thumb1` im lokalen Scope der Callback-Funktion eingeschlossen. Das ist gut. Wenn ich mit `var` gearbeitet hätte, dann wären `banner` und `thumb1` bei mir nicht lokal gewesen, sondern im globalen Scope. Das wäre schlecht.
Aber: das habe ich nicht. Ich habe `let` verwendet, und `let` hat – wie `const` auch – nicht Funktionsscope, sondern Blockscope. Damit sind auch bei mir `banner` und `thumb1` lokal im Schleifenrumpf.
Meine Variable `galleries` (die auch lieber ein `const` geworden wäre) ist übrigens nur der Einsteiger-Lesbarkeit wegen drin, ich hätte den zugewiesenen Wert auch direkt hinter dem `of` notieren können.
Was ist nun der Unterschied zwischen `.forEach` und `for...of`?
- `.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.
- `.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.
- `.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.
- 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.
- `.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.
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.
_Rolf_
--
sumpsi - posui - obstruxi