Signatur
Beschreibung
Ein NodeIterator merkt sich seine Position nicht als Index, sondern als Paar aus einem Referenzknoten (referenceNode) und einem Flag pointerBeforeReferenceNode. Das Flag sagt aus, ob der gedachte Zeiger direkt vor oder direkt nach dem Referenzknoten liegt. So lässt sich eindeutig festlegen, welcher Knoten beim nächsten Aufruf von nextNode() oder previousNode() geliefert wird.
Der Ablauf im Einzelnen:
- Direkt nach
document.createNodeIterator()istreferenceNodeder Wurzelknoten und das Flag isttrue. Der erstenextNode()-Aufruf liefert deshalb (sofern der Filter ihn akzeptiert) die Wurzel selbst. - Nach
nextNode()steht der Zeiger hinter dem gelieferten Knoten, das Flag ist alsofalse. - Nach
previousNode()steht der Zeiger vor dem gelieferten Knoten, das Flag ist alsotrue.
Im Alltag braucht man die Eigenschaft selten direkt. Sie hilft aber beim Debuggen von Traversierungslogik, beim Speichern und Wiederherstellen einer Iterationsposition und vor allem dann, wenn man verstehen will, wie sich ein Iterator verhält, sobald Knoten während der Iteration aus dem DOM entfernt werden. Der Browser verschiebt Referenzknoten und Flag in diesem Fall automatisch.
Rückgabewert
true, wenn der Zeiger vor dem referenceNode steht; false, wenn er dahinter steht. Die Eigenschaft ist schreibgeschützt.Beispiele
Wie sich das Flag bei nextNode() und previousNode() ändert
const list = document.createElement('ul');
list.innerHTML = '<li>A</li><li>B</li>';
const it = document.createNodeIterator(list, NodeFilter.SHOW_ELEMENT);
// Ausgangszustand: Zeiger steht vor der Wurzel
console.log(it.referenceNode.nodeName, it.pointerBeforeReferenceNode);
it.nextNode(); // liefert UL (Wurzel)
console.log(it.referenceNode.nodeName, it.pointerBeforeReferenceNode);
it.nextNode(); // liefert LI "A"
console.log(it.referenceNode.textContent, it.pointerBeforeReferenceNode);
it.previousNode(); // liefert erneut LI "A", Zeiger springt davor
console.log(it.referenceNode.textContent, it.pointerBeforeReferenceNode);
Referenzknoten wird während der Iteration entfernt
const list = document.createElement('ul');
list.innerHTML = '<li>A</li><li>B</li><li>C</li>';
document.body.append(list);
const it = document.createNodeIterator(list, NodeFilter.SHOW_ELEMENT);
it.nextNode(); // UL
it.nextNode(); // LI A
it.nextNode(); // LI B
const b = it.previousNode(); // LI B, Zeiger jetzt davor
console.log(b.textContent, it.pointerBeforeReferenceNode);
b.remove(); // Browser verschiebt den Referenzknoten auf den folgenden Knoten
console.log(it.referenceNode.textContent, it.pointerBeforeReferenceNode);
console.log(it.nextNode().textContent); // Iteration läuft nahtlos weiter
Debug-Hilfe: aktuelle Iterator-Position beschreiben
const describePosition = (iterator) => {
const node = iterator.referenceNode;
const label = node.nodeType === Node.ELEMENT_NODE
? `<${node.localName}>`
: node.nodeName;
return iterator.pointerBeforeReferenceNode
? `Zeiger vor ${label}`
: `Zeiger nach ${label}`;
};
const section = document.createElement('section');
section.innerHTML = '<h2>Titel</h2><p>Text</p>';
const it = document.createNodeIterator(section, NodeFilter.SHOW_ELEMENT);
console.log(describePosition(it));
it.nextNode();
it.nextNode();
console.log(describePosition(it));
// Wichtig · Fallstricke
- Schreibgeschützt: Eine Zuweisung wie
it.pointerBeforeReferenceNode = falsewird still ignoriert (im Strict Mode gibt es einenTypeError). Die Position lässt sich nur übernextNode()undpreviousNode()ändern. - Entfernte Knoten: Wird der Referenzknoten (oder einer seiner Vorfahren innerhalb der Wurzel) entfernt, passt der Browser
referenceNodeund das Flag an. Steht der Zeiger vor dem Knoten, rückt er auf den nächsten Knoten danach. Gibt es keinen, springt er auf den vorherigen Knoten und das Flag wirdfalse. Steht der Zeiger nach dem Knoten, wandert er auf den vorhergehenden Knoten in Dokumentreihenfolge. - Filter werden dabei ignoriert: Beim Verschieben nach einem Entfernen berücksichtigt der Browser weder
whatToShownoch denNodeFilter.referenceNodekann deshalb vorübergehend ein Knoten sein, den der Filter eigentlich ausschließt, zum Beispiel ein Textknoten. TreeWalkerhat kein solches Flag. Dort gibt es stattdessen die frei setzbare EigenschaftcurrentNode.- Kompatibilität: Wird in allen modernen Browsern unterstützt. Ältere Browser (z. B. Firefox vor Version 3.5 und Internet Explorer) boten die Eigenschaft nicht oder nur eingeschränkt an. Node.js hat kein eingebautes DOM, dort ist sie nur über Bibliotheken wie jsdom verfügbar.