Javascript Arrays forEach() / Objekte for in

Arrays mit forEach durchlaufen und Objekte mit for in

Die Iteration über Arrays und Objekte ist tägliches Brot beim Sammeln von Informationen und der Manipulation von Elementen.

Javascript forEach() ruft eine Funktion für jedes Element des Arrays auf. for in ist ein Sonderfall des for-Loops für die Iteration durch Arrays und Objekte.

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.

Komfortable Variationen der klassischen for-Iteration sind forEach und for in.

forEach ist die Wahl für Arrays, während for in als komfortable Wahl für Name-Wert-Paare gilt.

forEach()

forEach ist eine Funktion höherer Ordnung und erlaubt eine andere Funktion als Argument (callback).

forEach ruft eine Funktion für jedes Element eines Arrays auf und erinnert uns an das komfortable each in jQuery. Schön ist, dass man hier die Größe des Arrays nicht kennen muss.

array.forEach (callback [,thisObject]);

forEach ruft für jedes Element des Arrays eine Callback-Funktion auf und übergibt der Callback-Funktion den Wert des Arrays.

"use strict";
function maldrei (elem, index) {
	console.log (index + ' ' + elem * 3);
}
[4,8,16,22,102].forEach (maldrei);
                           ^
                           |
      callback-Funktion ---+
[Log] 0 12
[Log] 1 24
[Log] 2 48
[Log] 3 66
[Log] 4 306

forEach mit nodeLists

Auch wenn forEach dem eleganten each aus jQuery sehr ähnlich sieht – zusammen mit querySelectorAll hat forEach zum großen Leidwesen aller for i-Gelangweilten 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 die modernen Browser forEach auch auf einer NodeList.

Donut Toast Melone
Dieser Browser hat forEach mit NodeLists nicht auf dem Schirm
const elements = document.querySelectorAll("img");

elements.forEach(function(img, index) {
   console.log( img.getAttribute("alt") );
});

Allerdings bleibt IE11 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

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: Die Arrow Function geht IE11 auch noch 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.

Klassisches for oder forEach?

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 ). Und es ist sooo angestaubt …

const toys = [
    ["Teddy",18.90,200],
    ["Roller",24.50, 240],
    ,
    ["Puppe",19.00, 220],
    ["Puppenhaus",54.00]
];

const len = toys.length;
let i;
for (i=0; i<len; i++) {
   console.log ("for: " + toys[i]);
}

toys.forEach(function(toy, index) {
   console.log("foreach: " + toy);
});

In einem Array ohne Löcher würden beide Aufrufe die gleiche Ausgabe erzeugen. forEach() überspringt allerdings Löcher im Array (sparse arrays), die mit einem undefined überraschen können, ist kürzer und ausdrucksvoller.

[Log]  for: Teddy,18.9
[Log]  for: Roller,24.5
[Log]  for: undefined
[Log]  for: Puppe,19
[Log]  for: Puppenhaus,54

[Log]  forEach: Teddy,18.9
[Log]  forEach: Roller,24.5
[Log]  forEach: Puppe,19
[Log]  forEach: Puppenhaus,54

Spätestens, wenn wir es mit verschachtelten Aufrufen zu tun haben, ist forEach besser lesbar.

var colors = [
 [30, 90, 120],
 [40, 50, 60],    
 [65, 75, 85]
];

colors.forEach(function( index, obj ) {
   colors[obj].forEach(function( value, elem ) {
      console.log("elem key : elem " + elem + " value " + value);
   });
});

Die verschachtelten forEach-Anweisungen laufen über jedes Element des-Arrays, ohne dass wir uns um i und j und length kümmern müssen.

[Log]  elem key : elem 0 value 30
[Log]  elem key : elem 1 value 90
[Log]  elem key : elem 2 value 120
…
[Log]  elem key : elem 0 value 65
[Log]  elem key : elem 1 value 75
[Log]  elem key : elem 2 value 85

Javascript for in

for in durchläuft alle Elemente eines Objekts. Das Schöne an der for in-Anweisung ist, dass die Anzahl der Elemente nicht zuvor festgestellt werden muss, die Namen der Elemente nicht bekannt sein müssen und keine Endlos-Schleife zu befürchten ist.

In jeder Iteration wird einem Element des Objekts der Variablenname elem zugewiesen. Wenn alle Eigenschaften bearbeitet sind, endet der Loop.

for (name in MyObject) {
   name ist der Key des aktuellen Elements
   MyObject[name] ist der aktuelle Wert
   Anweisungen;
}

Javascript for in ist ein Sonderfall der for-Anweisung und dient allein der Iteration durch Arrays oder Objekte. Bei einem Array durchläuft die for … in-Anweisung alle Elemente eines Arrays.

Bei Objekten durchläuft for in alle Eigenschaften eines Objekts.

var text = "";
for (elem in window.navigator) {
   text = text + window.navigator[elem] + '\n';
}
alert(text);


	

for in kann in Zukunft durch forEach ersetzt werden, wenn Object.keys von allen Browsern zuverlässig unterstützt wird.

for in auch für JS Arrays?

Auch wenn for in als Schleife über Arrays bestens funktioniert, gilt for in bei Arrays nicht als gute Praxis. Bei einem Array kennen wir die Anzahl der Elemente und ein normaler for-Loop ist besser angebracht.

for-in-Loops laufen über die Eigenschaften von Objekten, nicht über die Indizes eines Arrays. Die Reihenfolge der Durchläufe ist als nicht garantiert. for in ist für die Iteration über die Elemente von Objekten gedacht.

Dennoch kann ein for-in-Loop über ein Array durchaus sinnvoll sein – wir sind wieder einmal bei Arrays mit Löchern (sparse arrays) – wenn Vorsicht vor undefined Elementen geboten ist.

var marr = [0,1,,,4,,6];
for (e in marr) {
   console.log ("sparse " + e);
}
for (var i=0; i<marr.length; i++) {
   console.log ("for " + marr[i]);
}

Ausgabe

[Log]  sparse 0 
[Log]  sparse 1 
[Log]  sparse 4 
[Log]  sparse 6 
[Log]  for 0 
[Log]  for 1 
[Log]  for undefined 
[Log]  for 4 
[Log]  for undefined 
[Log]  for 6 

Object.keys

Object.keys() gibt ein Array mit den Eigenschaften des Objektes zurück. Die Elemente des Arrays haben dieselben Reihenfolge wie in einer for in-Schleife

var obj = { 100: "Waldfrüchte", 50: "Beeren", 200: "Kulturpflanzen", 2: "Getreide"};

Object.keys(obj).forEach (function (val, key) {
   result1.innerHTML += "index[" + key + "] " + val + " " + obj[val] + "<br>";
});

for (var key in obj) {
   result2.innerHTML += "for in: " + key + ' : ' + obj[key] + "<br>";
}
forEach mit Object.keys

for in

Object.keys wird von allen modernen Browsern (IE ab Version 9) unterstützt.

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.

Zugunsten des for-Loops kann man anführen, dass for über alles läuft: Über Arrays, über HTML Collections (z.B. aus getElementsByName) und über Nodelists (aus querySelectorAll).

0
1
2
3
forEach