Javascript NodeList

HTMLCollection und NodeList sehen aus wie Arrays

querySelectorAll gibt eine statische Liste von Elementen (NodeList) zurück, die alten DOM-Methoden wie document.images, document.forms oder document.links gaben eine HTMLCollection zurück. Sowohl HTMLCollection als auch NodeList sehen aus wie Arrays, beide haben einen Index und eine length-Eigenschaft.

23-02-02 SITEMAP CSS HTML JS Basis JS Web Tutorial SVG

Javascript NodeLists sind keine Arrays

NodeLists sind eng mit Javascript Arrays verwandt, aber ihnen fehlen viele Methoden von Arrays wie valueOf, array push und array pop oder array join.

Trotzdem stehen für eine NodeList aus querySelectorAll () gut ein halbes Dutzend Alternativen für die Iteration über die Elemente zur Verfügung.

Demo-Bild Cup
Demo-Bild Buch
Demo-Bild Feder

Den Unterschied zwischen der NodeList aus querySelectorAll () und der HTMLCollection zeigt sich im Prototype in der Console des Browsers.

const list = document.querySelectorAll (".node");
console.log ("list", list);

  ▼ list 
  ▼ NodeList (3)
      0 <div class="node" title="cup">…</div>
      1 <div class="node" title="book">…</div>
      2 <div class="node" title="pen">…</div>
  ▼ NodeList Prototype
     constructor: function()
     entries()
     forEach()
     item(index)
     keys()
     length: 3
     values()
     Symbol(Symbol.iterator)()
     Symbol(Symbol.toStringTag): "NodeList"

const collection = document.getElementsByClassName ("node");
console.log ("collection", collection);

  ▼ collection 
  ▼ HTMLCollection (3)
      0 <div class="node" title="cup">…</div>
      1 <div class="node" title="book">…</div>
      2 <div class="node" title="pen">…</div>
  ▼ HTMLCollection Prototype
     constructor: function()
     index([index])
     length: 3
     namedItem([name])
     Symbol(Symbol.iterator)()
     Symbol(Symbol.toStringTag): "NodeList"

querySelectorAll und for-Loop

Die gute alte schrittweise for-Schleife: Das ist die älteste Technik, nicht so elegant wie neuere Methoden, aber unterstützt von allen Browsern und eine der Schnellsten.

const nodes = document.querySelectorAll(".node");
for (let i=0; i < nodes.length; i++) {
  console.log ("title " + nodes[i].getAttribute("title"));
}

Ein einzelnes Element fischt nodes[i] mit dem Index aus der NodeList – nicht anders als bei einem Array.

let book = nodes[1];

NodeList.values()

NodeList.values() gibt einen Iterator zurück, der über alle Werte des NodeList-Objekts läuft.


const ul = document.createElement ("ul");
const l1 = document.createElement ("li");
const l2 = document.createElement ("li");
const l3 = document.createElement ("li");
l2.innerHTML = "Earthday";
l1.innerHTML = "Wildfang";
l2.innerHTML = "Arche";

var list = ul.childNodes;

for (const elem of list.values()) {
	console.log( elem );
	document.querySelector(".nlist").innerHTML += elem.nodeName + " ";
}

nodeList.item greift auf einzelne Elemente einer Nodelist zu.

elemContent.innerHTML += list.item(2).textContent;



		

querySelectorAll mit for of

Eigentlich ist for of nur eine Erweiterung des normalen for-Loops aus ES1. for of läuft über Strings, Arrays und NodeList. Wird von den immergrünen Browsern unterstützt, aber nicht von IE11 und älter.

for (const node of nodes) {
   console.log (nodeElem.innerHTML);
}

Nodelists mit forEach

Die modernen Browser bis auf IE11 unterstützen forEach () auf NodeLists (Polyfill für forEach in NodeLists mit IE11) auf Github.

forEach und for of sind ausdrucksvoller, besser lesbar im Script und forEach überspringt Löcher in sparse Arrays.

Donut Toast Melone
const elements = document.querySelectorAll (".nodelist img");

elements.forEach (function(img, index) {
   img.setAttribute ("style","border:2px solid gainsboro");
});

spread-Operator für NodeLists

Die drei Punkte der Spread-Syntax wandeln eine NodeList in ein Array um und eröffnen der NodeList Array-Methoden höherer Ordnung wie array.filter().

const list = document.querySelectorAll (".imgnode");
const alt = [...list].filter ((item) => item.alt === "Toast");
console.log ("alt", alt); // [Log] alt – [] (1) 

Dynamische / statische NodeList

Die älteren DOM-Methoden getElementsByClassName, getElementsByTagName und getElementsByName liefern eine ähnliche Liste, allerdings als dynamische HTMLCollection. Das dynamische an der HTMLCollection: Wenn neue Elemente in die Sammlung eingefügt oder Elemente gelöscht werden, ändert sich auch die Liste.

Dynamische NodeLists haben ihre eigenen Vorteile gegenüber Arrays: Sie haben ein automatisches Update, wenn neue Elemente in das DOM eingefügt oder Elemente aus dem Dokument gelöscht werden. querySelectorAll gibt eine statische NodeList zurück, keine dynamische HTMLCollection mit Auto-Update.

let nodelist = document.querySelectorAll(".node");
let collection = document.getElementsByClassName("node");

let nodelistLength = nodelist.length;       => 3
let collectionLength = collection.length;   => 3

Wenn ein neues Element eingefügt wird:

let cat = document.createElement("div");
cat.classList.add("node");
document.querySelector(".noderow").appendChild(cat);

//console.log ( nodelist.length );    => 3
//console.log ( collection.length );  => 4

NodeList oder HTMLCollection

Sowohl Collections als auch Nodelists sind Sammlungen oder Auswahlen von DOM-Nodes. Während eine NodeList aus jeder Art von Knoten bestehen kann, enthält eine HTMLCollection nur Element Nodes – Elementknoten.

Neben der Frage statisch oder dynamisch? unterscheiden sich NodeList und HTMLCollection durch ihre Methoden. Ob eine Liste, die von einer der Sammel-Methoden zurückgegeben wird, eine Node List oder eine HTML Collection ist, stellt die Abfrage nach dem Constructor fest.

console.log ( document.querySelectorAll(".node").constructor.name);         => NodeList
console.log ( document.getElementsByClassName("node").constructor.name);   => HTMLCollection
console.log ( document.querySelector(".noderow").children.constructor.name);     => HTMLCollection
console.log ( document.querySelector(".noderow").childNodes.constructor.name);   => NodeList
getElementsByClassName () HTMLCollection live
getElementsByTagName () HTMLCollection live
childNodes () NodeList nicht live
children () HTMLCollection live
getElementsByName () HTMLCollection live
querySelectorAll () NodeList nicht live

NodeList-Methoden

NodeList.item ( i )
Element der NodeList am Index i
NodeList.entries ()
Elemente der Nodelist
NodeList.forEach ()
Iteriert über alle Elemente der NodeList
NodeList.keys ()
Schlüssel, Index der Elemente
NodeList.values ()
Object Array Iterator

Die Methoden entries(), keys() und values() geben einen Iterator zurück. Der Iterator kam mit ES2015 - IE11 und älter bleiben außen vor.

const nodes = document.querySelectorAll(".node");
for (const node of nodes.entries()) {
	console.log('node entries: ', node);
};

for (let key of nodes.keys()) {
	console.log ("keys " + key);
}

console.log (nodes.item(2) );

Array.from: NodeList zu Array mit ES 2015

Array.from erzeugt ein Array aus Array-ähnlichen Objekten und wird die einfachste Technik, um ein Array aus einer NodeList zu generieren.

Damit lassen sich Array-Methoden wie array.map () und array.filter () auch auf NodeLists und HTML-Collections nutzen.

<div class="gallery">
	<div data-img="img/scene1-s.jpg"></div>
	<div data-img="img/scene2-s.jpg"></div>
	<div data-img="img/scene3-s.jpg"></div>
	<div data-img="img/scene4-s.jpg"></div>
</div>
Nähzeug
Stoffmuster
Serviette
Mango
const divs = Array.from(document.querySelectorAll("div.fruity"));

const gallery = divs.map (function (item) {
	item.innerHTML = `<img src='${item.getAttribute("data-img")}'>`;
	return item.getAttribute("data-img");
});

gallery.forEach(function (elem) {
	document.querySelector("#letta").innerHTML += elem + " ";
});


NodeList zu Array (legacy – alte Browser)

Für Browser, die Array.from noch nicht unterstützen (z.B. IE11), gibt es Tipps von allen Seiten in jeglicher Couleur.

ECMAScript 6 compatibility shims for legacy JavaScript engines