The Document.querySelectorAll()
method and the Node.childNodes
property both return a NodeList. But the former returns a static NodeList, while the latter returns a live NodeList. This is an important difference to understand, else your code might behave in unexpected ways.
Static NodeLists
Static NodeLists are unaffected by future changes to the DOM.
Imagine the following HTML...
<body>
<h1>This is a heading.</h1>
<p>This is a paragraph.</p>
<p>This is another paragraph.</p>
<p>This is yet another paragraph.</p>
</body>
...then consider the following JavaScript:
// Select all paragraphs inside the body
var paragraphs = document.body.querySelectorAll("p");
// Log the number of paragraphs inside the NodeList (3)
console.log(paragraphs.length);
This logs 3
, which is what we'd expect, since there are three paragraph elements inside the NodeList.
Look what happens if we add another paragraph to the body
:
// Create a new paragraph
var newParagraph = document.createElement("p");
// Add the new paragraph to the body
document.body.appendChild(newParagraph);
// Log the number of paragraphs (3)
console.log(paragraphs.length);
Although there are now four paragraphs inside the body
element, the NodeList still contains only three. This is because static NodeLists do not pick up further changes to the DOM.
Live NodeLists
Live NodeLists are affected by further changes to the DOM.
Assume the same HTML as before.
Let's save the body
element's childNodes
property to a variable, then log its length:
// Get all child nodes inside the body
var childNodes = document.body.childNodes;
// Log the number of child nodes (9)
console.log(childNodes.length);
This returns 9
since there are four element nodes plus five whitespace nodes.
(The childNodes
property considers all types of node including whitespace, comments, etc—not just HTML elements.)
But look what happens this time if we add another element:
// Create a new paragraph
var newParagraph = document.createElement("p");
// Add the new paragraph to the body
document.body.appendChild(newParagraph);
// Log the number of child nodes (10)
console.log(childNodes.length);
There are now ten child nodes inside the body
element.
Because the childNodes
property returns a live NodeList, it gets updated automatically.
Even though I didn't manually update the childNodes
variable, its length
property shows the updated number, which is 10
.
In practical terms
As they explain in the MDN Web Docs:
It's good to keep this distinction in mind when you choose how to iterate over the items in the
NodeList
, and whether you should cache the list'slength
.