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