Start · Sprachen · JavaScript · Referenz · NodeList.forEach()

NodeList.forEach()

Methode

Ruft eine Rückruffunktion einmal für jeden Knoten einer <code>NodeList</code> in Dokumentreihenfolge auf.

seit JavaScript Baseline: alle modernen Browser (seit ca. 2017; ni Kategorie: webapi

Signatur

NodeList.prototype.forEach(callback, thisArg)

Beschreibung

Mit NodeList.prototype.forEach() durchläufst du alle Knoten einer NodeList, ohne sie vorher in ein Array umzuwandeln. Typischerweise stammt die Liste aus document.querySelectorAll() oder Node.childNodes. Für jeden Eintrag wird die Rückruffunktion mit dem aktuellen Knoten, seinem Index und der Liste selbst aufgerufen.

Die Methode verhält sich wie Array.prototype.forEach(): Sie gibt undefined zurück und lässt sich weder mit break noch mit return vorzeitig abbrechen. Wenn du abbrechen, filtern oder abbilden willst, wandle die Liste mit Array.from() oder dem Spread-Operator in ein echtes Array um oder verwende eine for...of-Schleife.

Wichtig ist der Unterschied zwischen statischen und live NodeLists: Die Liste aus querySelectorAll() ist statisch. Änderungen am DOM während des Durchlaufs wirken sich also nicht auf sie aus. childNodes ist dagegen live. Entfernst oder fügst du dort während der Schleife Knoten ein, können Einträge übersprungen oder doppelt verarbeitet werden.

Parameter

Name Typ Default Beschreibung
$callback Pflicht (currentValue: Node, currentIndex: number, listObj: NodeList) => void Funktion, die für jeden Knoten aufgerufen wird. Sie bekommt drei Argumente: currentValue (den aktuellen Knoten), currentIndex (seinen Index) und listObj (die NodeList, auf der forEach() aufgerufen wurde).
$thisArg any undefined Wert, der beim Ausführen von callback als this gilt. Bei Pfeilfunktionen hat er keine Wirkung, weil diese this aus dem umgebenden Gültigkeitsbereich übernehmen.

Rückgabewert

Typ
undefined
Beschreibung
Die Methode liefert nichts zurück und lässt sich deshalb nicht verketten.

Beispiele

Allen Buttons eine Klasse und einen Klick-Handler geben

const buttons = document.querySelectorAll('button.aktion');

buttons.forEach((button, index) => {
  button.classList.add('bereit');
  button.addEventListener('click', () => {
    console.log(`Button ${index} geklickt: ${button.textContent}`);
  });
});
Button 0 geklickt: Speichern (nach Klick auf den ersten Button)

Kindknoten inklusive Textknoten untersuchen

const liste = document.createElement('ul');
liste.innerHTML = '<li>Äpfel</li>\n<li>Birnen</li>';

liste.childNodes.forEach((node, i) => {
  console.log(i, node.nodeName, JSON.stringify(node.textContent));
});
0 LI "Äpfel" 1 #text "\n" 2 LI "Birnen"

thisArg nutzen, um in einem Objekt zu sammeln

const statistik = {
  anzahl: 0,
  zaehle(node) {
    if (node.nodeType === Node.ELEMENT_NODE) this.anzahl++;
  }
};

document.body.childNodes.forEach(statistik.zaehle, statistik);
console.log(`Elemente direkt im body: ${statistik.anzahl}`);
Elemente direkt im body: 3 (abhängig vom Dokument)

Vorzeitig abbrechen: stattdessen for...of verwenden

const felder = document.querySelectorAll('input[required]');

// forEach kann nicht abbrechen – for...of schon
let erstesLeeresFeld = null;
for (const feld of felder) {
  if (!feld.value.trim()) {
    erstesLeeresFeld = feld;
    break;
  }
}
erstesLeeresFeld?.focus();

// Für filter/map vorher in ein Array umwandeln
const namen = [...felder].map((f) => f.name);
console.log(namen);
["vorname", "nachname", "email"] (abhängig vom Formular)

// Wichtig · Fallstricke

  • Nur forEach, kein vollständiges Array: Eine NodeList hat zwar forEach(), entries(), keys() und values(), aber weder map() noch filter() oder reduce(). Hier hilft Array.from(nodeList) oder [...nodeList].
  • HTMLCollection hat kein forEach: getElementsByClassName(), getElementsByTagName() und element.children liefern eine HTMLCollection. Ein Aufruf von .forEach() darauf wirft einen TypeError.
  • Live-Listen: Veränderst du childNodes während des Durchlaufs, etwa durch node.remove(), werden Einträge übersprungen. Kopiere die Liste vorher: [...el.childNodes].forEach(n => n.remove()).
  • Kein Abbruch, kein await: return im Callback überspringt nur den aktuellen Eintrag. Ist der Callback async, wartet forEach nicht auf die Promises. Für sequenzielles Warten nimm for...of mit await.
  • Kompatibilität: Im Internet Explorer fehlt die Methode. Für ältere Umgebungen reicht ein Polyfill: NodeList.prototype.forEach ??= Array.prototype.forEach;