for oder while?
while-Schleifen (auch for loop) werden eingesetzt, wenn die Zahl der Durchläufe am Anfang nicht bekannt ist. Allerdings ziehen wir heute forEach oder for of vor, da wir uns nicht um die Zahl der Loops kümmern müssen und nicht in die Schreckliche Unendliche Schleife geraten.
Eine for-Anweisung in Javascript basiert auf einer Variablen für den Index und führt Anweisungen in abgezählten Schritten durch (Iteration), bis eine Bedingung nicht mehr zutrifft.
Klassische for-Anweisung
Anders als die Varianten der while-Schleife wird die Variable innerhalb der Increment-Anweisung automatisch rauf- oder runtergezählt. Im Anweisungsblock der for-Anweisung muss keine Anweisung für das sichere Ende der Schleife sorgen.
Alle Zutaten sind am Anfang der Schleife in einer Klammer gelistet. Das macht die for-Anweisung so gut lesbar.
Schritt-Anweisung (Increment) │ ▼ for ( let i=0; i<=9; i++ ) { ▲ ▲ │ │ │ └─── Bedingung │ └─── Anfangs-Ausdruck … Anweisungen: Mach was mit i … }
Der Anfangs-Ausdruck initialisiert einen oder mehrere Zähler – fast immer auf einer Zählvariablen, z.B. let i=0;. Der Anfangs-Ausdruck erlaubt eine beliebig komplexe Syntax.
Die Bedingung legt fest, wann die Zielgröße der Zählvariablen erreicht ist, z.B. i<10;.
Die Increment-Anweisung erhöht die Zählvariable (z.B. i++) oder zählt sie herunter (z.B. i--), kann aber auch mit einer Schrittweite 17 oder einer komplexe Funktion wie myFunction(i) umgehen.
Ablauf der for-Anweisung
Die for-Anweisung wird nach dem folgenden Schema durchgeführt:
- Der Anfangs-Ausdruck wird ausgeführt.
- Die Bedingung wird geprüft (evaluiert). Wenn der Wert der Bedingung true ist, werden die Anweisungen in der for-Anweisung ausgeführt. Wenn der Wert der Bedingung false liefert, endet die for-Anweisung. Wenn keine Bedingung notiert ist, gilt die Bedingung als true.
- Die Anweisungen werden durchgeführt.
- Die Increment-Anweisung wird ausgeführt und die Kontrolle wird an Schritt 2 übergeben.
let text = ''; let zahl = 10; for ( let i=0; i<=zahl; i++ ) { text = text + i + ' mal 3 ist ' + i*3 + '\n'; } console.log (text);
0 mal 3 ist 0 1 mal 3 ist 3 2 mal 3 ist 6 … 9 mal 3 ist 27 10 mal 3 ist 30
Die Variable text speichert die Aufgabe und das Ergebnis jedes Laufs durch den Block der for-Anweisung. Die Variable zahl gibt vor, wie oft der for-Block aufgerufen wird.
for-Loop: Anfang und Schrittweite
for-Anweisungen beginnen nicht notwendigerweise mit dem Index 0. Das Increment (Schrittweite) muss nicht 1 sein. Ein Skript würde den Block der folgenden for-Anweisung vier Mal durchführen: für i=3, i=8, i=13 und i=18.
let index = 3; let jump = 5; let i; for ( i=index; i<23; i+=jump ) { // oder i=i+jump // Anweisungen }
Zu weit gelaufen
Das passiert schnell: Die Iteration geht um 1 zu weit, weil sich ein Tippfehler eingeschlichen hat: i <= fruits.length statt i < fruits.length.
const fruits = [ {name: "Erdbeeren"}, {name: "Pfirsiche"}, {name: "Kirschen"} ]; for (let i=0; i <= fruits.length; i++) { console.log (`i value: ${i} | Früchte:`, fruits[i]) }
[Log] i value: 0 | Früchte: – {name: "Erdbeeren"} [Log] i value: 1 | Früchte: – {name: "Pfirsiche"} [Log] i value: 2 | Früchte: – {name: "Kirschen"} [Log] i value: 3 | Früchte: – undefined
Mit einem forEach-Loop, for / of oder array.map wäre das nicht passiert.
for (let i) vs for (var i)
Mit der alten Variablen-Deklaration var i existiert die Variable i nach dem Ende des for-Loops weiter. Das macht keinen Sinn und kann zu Fehlern führen.
Mit for (let i=x …) existiert i nur innerhalb der for-Anweisung und ist damit die bessere Lösung für for-Schleifen.
Verschachtelte for-Schleifen
for-Anweisungen lassen sich ineinander verschachteln. Zweidimensionale Arrays werden mit verschachtelten for-Schleifen durchlaufen.
let colors = [ [30, 90, 120], [40, 50, 60], [65, 75, 85] ]; let i; for ( i=0; i<colors.length; i++ ) { for (let j=0; j<colors[i].length; j++) { console.log ("colors [i][j] "+" colors ["+i+"]["+j+"]" + colors [i][j]); } }
Die innere for-Schleife gibt jedes Element des Arrays aus:
[Log] colors [i][j] colors [0][0] 30 [Log] colors [i][j] colors [0][1] 90 [Log] colors [i][j] colors [0][2] 120 … [Log] colors [i][j] colors [2][0] 65 [Log] colors [i][j] colors [2][1] 75 [Log] colors [i][j] colors [2][2] 85
Variationen des for-Loops
In den jüngeren Javascript-Versionen hat die for-Schleife zahlreiche Ableger: for in, for of, forEach. for in ist allerdings für Arrays nicht unbedingt geeignet, da die Reihenfolge der Elemente nicht garantiert ist. for of ist mit ES2015 hinzugekommen und iteriert über iterierbare Sammlungen - z.B. über die NodeList aus querySelectorAll.
Dünnbesetzte Arrays – sparse Arrays
Der Index eines Arrays muss nicht fortlaufend sein.
let arr = ["Anton", "Berta", "Claudia"]; arr[9] = "Zara"; for (let i=0; i<arr.length; i++) { console.log ("i " + i + " " + arr[i]); } for (let item of arr ) { console.log ("item of " + item); } for (let item in arr ) { console.log ("item in " + item); }
Die for-Schleife wird das Array 9 mal durchlaufen. An den nicht besetzten Stellen gibt arr[i] undefined zurück.
Genauso wird auch for of 9 mal durchlaufen – mit dem Rückgabewert undefined bei jedem Loch des Arrays.
for in wird vier mal durchlaufen und gibt "Anton", "Berta", "Claudia" und "Zara" zurück, aber nicht unbedingt in dieser Reihenfolge. for-in iteriert über die Eigenschaften eines Objekts und Arrays sind letztendlich Objekte mit einem ganzzahligen Schlüssel. for-in klingt jetzt schneller, weil es nur vier mal durchlaufen wird, ist es aber nicht.
forEach
Seit ES5 gibt es forEach für Arrays. Das klassische for (i=0; i<length; i++) braucht eine Variable i als Zähler, muss auf die Anzahl der Array-Element prüfen und das aktuelle Element mit [i] ansprechen. Das läßt viel Raum für potentielle Vertipper (z.B. lenght statt length) und Fehler (z.B. i).
forEach() überspringt Löcher im sparse Arrays, wir müssen nicht wissen, wie groß das Array ist. forEach ist kürzer und ausdrucksvoller.