Javascript NodeList

DOM nodeLists sind keine Arrays

querySelectorAll gibt eine statische Liste von Elementen (NodeList) zurück, die beim Löschen oder Einfügen neuer Elemente ohne Update bleibt.

Jede NodeList hat eine length-Eigenschaft, einen Index, der bei 0 beginnt und der Zugriff auf einzelne Elemente funktioniert wie bei einem Array.

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.

Ein for-Loop durchläuft die NodeList in gleicher Weise wie ein Array:

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

Ein einzelnes Element fischt man mit den Index aus der NodeList – nicht anders als bei einem Array.

let book = nodes[1];

Nodelists mit forEach

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

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

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

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

Dynamische / statische NodeList

Die älteren DOM-Methoden getElementsByClassName, getElementsByTagName und getElementsByName liefern eine ähnliche Liste, allerdings als dynamische HTMLCollection.

Eine HTMLCollection ist dynamisch: 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 Elemente 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.

Neben der Frage statisch oder dynamisch unterscheiden sich NodeList und HTMLCollection durch ihre Methoden. Ob eine Liste, die von einer der Sammler-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
NodeList.entries
NodeList.forEach
NodeList.keys
NodeList.values

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

Apfel
Birne
Traube
Beere
let divs = Array.from(document.querySelectorAll("div.fruity"));
divs.forEach(function (key) {
	console.log ("div.fruity : " + key.innerHTML);
});



NodeList zu Array (legacy)

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

let myNodeList = document.querySelectorAll("div");
let myArray = [];
for (let i=0; i < myNodeList.length; i++) {
    let self = myNodeList[i];
    myArray.push(self);
}

oder 

for (let i=0; i < myNodeList.length; i++) {
    myArray[i] = myNodeList[i];
}

Das ist einfach, stabil und erhält die NodeList, hat aber keinen guten Ruf, denn diese Methode ist langsam. Wenn's schnell gehen muss:

let myArray = [];
let myNodeList = document.querySelectorAll('div');
for(let i = myNodeList.length; i--; myArray.unshift(myNodeList[i]));

Eleganter als ein for-Loop:

let divs = Array.prototype.slice.call(document.querySelectorAll('div'));

oder

let myNodeList = document.getElementsByClassName('.myClass'),
	myArray = [].slice.call(myNodeList);

gibt eine exakte Kopie zurück.

DOM Scripting P UL DIV FORM IMG HTML BODY