Javascript Arrays forEach ()

forEach Arrays durchlaufen

forEach() ist eine Variante des klassischen for-Loops. forEach ruft eine Callback-Funktion für jedes Element des Arrays auf und ist intuitiver als die klassische for-i-Iteration: Die Länge des Arrays muss nicht bekannt sein.

18-12-15 SITEMAP CSS HTML JS Basis JS Web Tutorial SVG

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 mehrere 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 ((book, index) => {
  console.log(`i:${index} | Autor:`, book);
});
Callbackfunktion als Arrow-Funktion
books.forEach (function (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.

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.

Donut
Toast
Melone
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)
});

forEach-Polyfill für IE11

Allerdings bleibt IE11 (Release 2013!) beim forEach mit NodeList weiterhin außen vor. Damit auch IE11 forEach mit NodeLists abarbeitet, gibts ein Polyfill.

if (window.NodeList && !NodeList.prototype.forEach) {
   console.info("forEach Polyfill für IE11");
   NodeList.prototype.forEach = function (callback, thisArg) {
      thisArg = thisArg || window;
      for (var i = 0; i < this.length; i++) {
         callback.call(thisArg, this[i], i, this);
      }
   };
}

Quelle: bob-lee / polyfill-ie11-nodelist-foreach.js

Die Eigenschaft prototype fügt einem Javascript-Objekt neue Eigenschaften und Methoden hinzu. Javascript Polyfills nutzen Prototyping, um alten Browsern neue Eigenschaften und Methoden beizubringen.

forEach in 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.

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 deutlich langsamer als ein klassischer for-Loop, was sich aber erst bei Arrays mit vielen Elementen bemerkbar macht.