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.

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

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

var nodes = document.querySelectorAll(".node");
for (var 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.

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

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

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

Wenn ein neues Elemente eingefügt wird:

var 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

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

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

oder 

for (var 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:

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

Eleganter als ein for-Loop:

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

oder

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

gibt eine exakte Kopie zurück.

DOM Scripting P UL DIV FORM IMG HTML BODY