forEach() mit callback
Eine klassische for-Anweisung in Javascript basiert auf einer Variablen für den Index und führt Anweisungen in abgezählten Schritten durch (Interation), bis eine Bedingung nicht mehr zutrifft. Da Arrays ebenfalls auf einem Index basieren, sind for-Iterationen für Arrays wie geschaffen.
const books = [ { autor: 'Jane Austen' }, { autor: 'Jared Diamond'}, { autor: 'Dorothy L. Sayers'} ]
Wie bei vielen Javascript-Methoden gibt es für for-Loops vielerlei Optionen:
Klassischer for-Loop
for (let i=0; i<books.length; i++) { console.log(`i:${i} | Autor:`, books[i]); }
Aufruf der Callback-Funktion
books.forEach (autoren); function autoren (item) { console.log ("Favorit " + item.autor) }
Callbackfunktion im foreach
books.forEach (function (book, index) { console.log(`i:${index} | Autor:`, book); });
Callbackfunktion als Arrow-Funktion
books.forEach ((book, index) => { console.log(`i:${index} | Autor:`, book); });
4 x for-Loop, ein Ergebnis
Das Ergebnis ist in allen Variationen dasselbe, aber beim forEach sind weniger Informationen erforderlich: Die Größe des Arrays muss nicht angegeben werden, kein Startpunkt und keine Schrittweite.
Und ein weiterer Punkt für forEach: Die Callback-Funktion verschließt die Variable im Scope des forEach. Würde eine Variable außerhalb definiert und innerhalb von forEach benutzt, würde die Variable außerhalb davon nicht berührt und ihren Wert behalten.
[Log] i : 0 | Autor: – {autor: "Jane Austen"} (foreach.html, line 164) [Log] i : 1 | Autor: – {autor: "Jared Diamond"} (foreach.html, line 164) [Log] i : 2 | Autor: – {autor: "Dorothy L. Sayers"} (foreach.html, line 164)
forEach ruft für jedes Element des Arrays eine Callback-Funktion auf und übergibt der Callback-Funktion den Wert des Arrays. Die Callback-Funktion (book, index) => {…} sorgt auch dafür, dass alle Variablen innerhalb des forEach-Scopes bleiben.
Wenn die Aktionen auf dem Array umfangreicher werden, gibt es eine weitere Schreibweise für den Einsatz von forEach:
function autorlist (autor, index) { console.log (index + ' ' + books[index].autor); } books.forEach (autorlist); ^ | callback-Funktion books.slice(2, 5).forEach(autorlist);
forEach ist einfacher, wenn wir das Array vollständig durchlaufen wollen. Soll nur ein Teil des Arrays behandelt werden, kommt z.B. array.slice zum Einsatz.
Wenn die Callback-Funktion nicht gebraucht wird, steht seit ES6 der for-of-Loop bereit.
Es gibt kein break für forEach
Da muss man durch – aber es gibt eine gute Alternative: array.some() und array.every().
forEach mit querySelectorAll – nodeLists
Auch wenn forEach dem eleganten each aus jQuery sehr ähnlich sieht – forEach mit querySelectorAll hat zum großen Leidwesen aller for i-Genervten lange Zeit nicht funktioniert:
document.querySelectorAll('h3').forEach (buildIndex);
querySelectorAll sammelt und filtert HTML-Elemente, aber gibt kein Array zurück, sondern eine NodeList. Eine NodeList sieht aus wie ein Array, aber ihr haben bis ECMAScript 2015 viele Methoden von Arrays gefehlt, darunter auch forEach.
Jetzt unterstützen alle modernen Browser forEach auch auf bei NodeLists.
Dieser Browser hat forEach mit NodeLists nicht auf dem Schirm
const elements = document.querySelectorAll(".nodelist img"); elements.forEach(function(img, index) { let figcaption = document.createElement("figcaption"); figcaption.textContent = img.getAttribute ("alt") img.parentElement.appendChild (figcaption) });
Mit foreach über Object
Object.keys() gibt ein Array mit nummerierten Eigenschaften zurück, so dass foreach über jeden Key / Schlüssel laufen kann.
const countrys = { germany: "🍖", italy: "🍕", denmark: "🍞", austria: "🍰" } Object.keys(countrys).forEach(key => { console.log(key, countrys[key]); });
Das funktioniert in gleicher Weise mit Object.values().
Und dann gibt es auch noch Object.entries.
Object.entries(countrys).forEach(entry => { const [key, value] = entry; console.log(key, value); });
forEach als Arrow Function
Und da wir gerade bei IE und forEach sind: Es gibt auch die kompakte Schreibweise mit dem Pfeil, die Arrow-Funktion. Ein Blick ins Ofenrohr des Internets: Die Arrow Function geht IE11 ebenfalls gegen den Strich.
elements.forEach (img => console.log (img.getAttribute("alt")));
querySelectorAll gibt eine NodeList zurück, getElementsByClassName, –ByName und -TagName geben eine HTML Collection zurück. forEach auf HTMLCollection gibts nicht.
foreach über zwei Arrays
Zwei Arrays gleicher Größe zusammenführen
const animalname = ["Krokodil", "Katze", "Ratte", "Schlange", "Wal"]; const animalimg = ["🐊", "🐈" , "🐀" , "🐍 ", "🐋" ]; animalname.forEach((item, index) => { const image = animalimg[index]; document.querySelector(".animals").innerHTML += item + " + " + image + "
"; });
for of – Einer für alle
Noch ein junger Sproß der for-Familie: for / of iteriert auch ohne Callback über Arrays, Strings, Sets, nodeLists, Objekte, HTML Collections – eben über alles, was zählbar ist.
for (const item of elements) { console.log( item.alt ); }
In for-of-Loops kann die Variable als const deklariert sein. Die Iterationsvariable (item) kann trotzdem in jedem Iterationsschritt anders sein, sie kann nur nicht während der Iteration geändert werden. for-of mit Index geht auch:
const arr = ["Hund", "Katze", "Maus", "Esel"]; for (const [index, elem] of arr.entries()) { console.log(`${index} -> ${elem}`); }
Am Rande: `${index} -> ${elem}` ist ein Template String oder Template Literal, das Variablen mit $ direkt in Strings einsetzt.
[Log] 0 -> Hund [Log] 1 -> Katze [Log] 2 -> Maus [Log] 3 -> Esel
for of funktioniert nicht nur mit Arrays, sondern auch mit Javascript Sets. Sets ähneln Arrays, aber können nur eindeutige Elemente enthalten, kein Wert kann zweimal vorkommen.
Der klassische for-Loop
Der altgediente for-Loop hat weiterhin seine Darseinsberechtigung bei numerischen Arrays: Die Reihenfolge ist garantiert, for kann rückwärts laufen. Der klassische for-Loop kann mit break vorzeitig verlassen werden, wenn z.B. ein gesuchtes Element an Stelle 10 in einem Array der Länge 100 bereits gefunden wurde.
Zugunsten des for-Loops kann man anführen, dass for (let i) über alles läuft: Über Arrays, über HTML Collections (z.B. aus getElementsByName) und über Nodelists (aus querySelectorAll).
for (let j=0; j<divs.length; j++) { divs[j].textContent = j; if (j == index) break; }
Am Ende ist forEach langsamer als ein klassischer for-Loop, was sich aber erst bei Arrays mit vielen Elementen bemerkbar macht.