<div id=”container”><div class="divy">...</div><div class="divy">...</div><div class="divy">...</div><div class="divy">...</div></div>
During the good jQuery days, you could just do
I was trying to do the same thing using the native DOM selector API and was in for a surprise
const childDivs = document.querySelectorAll('.divy')
Array.isArray(childDivs) //=> falsechildDivs.constructor.name //=> NodeList
Okay let’s try one of the
getElementBy% methods and check what is returned
const childDivsAgain = document.getElementsByClassName('divy')
Array.isArray(childDivs) //=> falsechildDivs.constructor.name //=> HTMLCollection
Now what are
Let’s try to understand the difference between HTMLCollection and NodeList first.
An HTMLCollection is a list of nodes. An individual node may be accessed by either ordinal index or the node’s name or id attributes.
Collections in the HTML DOM are assumed to be live meaning that they are automatically updated when the underlying document is changed.
HTML Collections are always “in the DOM”, whereas a NodeList is a more generic construct that may or may not be in the DOM.
A NodeList object is a collection of nodes. The NodeList interface provides the abstraction of an ordered collection of nodes, without defining or constraining how this collection is implemented. NodeList objects in the DOM are live or static based on the interface used to retrieve them
Let’s test the specification with relevant code to understand more
let parentDiv = document.getElementById('container')
let nodeListDivs = document.querySelectorAll('.divy')let htmlCollectionDivs = document.getElementsByClassName('divy')
nodeListDivs.length //=> 4htmlCollectionDivs.length //=> 4
//append new child to containervar newDiv = document.createElement('div');newDiv.className = 'divy'parentDiv.appendChild(newDiv)
nodeListDivs.length //=> 4htmlCollectionDivs.length //=> 5
We can see that the HTMLCollection is literally live, in the sense, any change to DOM is updated automatically and available in the collection.
Not all NodeList objects are static. For example,
document.getElementByName will return a live NodeList.
But remember that neither
NodeList support the array prototype methods like
splice methods . Iterator methods like
forEach have been recently added though and latest browsers might support them.
I came to know about this difference, when I was trying to use the dragula drag-n-drop library to add selected components to the library
let draggableLists = document.querySelectorAll('div.draggable')dragula(draggableLists); //will not work
This will not work as expected as the
const nodelist = document.querySelectorAll(‘.divy’)const divyArray = Array.from(nodelist)
const nodelist = document.querySelectorAll(‘.divy’)const divyArray = Array.prototype.slice.call(nodelist)
And I like this one. If you are using ES6, you can just use the spread operator
const divyArray = […document.querySelectorAll(‘.divy’)]
Now, let’s apply that to the dragula api to make it work
So when do you really convert NodeList to an array? Well, it depends on your usecase. If you really want an iterator to the latest updated DOM at all times, you should use the
HTMLCollection as it is without converting it to an array.
If you liked this post, pls follow me on twitter for more updates..