NodeList
objects are collections of nodes such as those returned by Node.childNodes
and the document.querySelectorAll
method.
Properties
length
- The number of nodes in the NodeList.
Methods
item ( idx )
- Returns an item in the list by its index, or
null
if the index is out-of-bounds; can be used as an alternative to simply accessingnodeList[idx]
(which instead returnsundefined
whenidx
is out-of-bounds).
Description
A sometimes-live collection
In some cases, the NodeList
is a live collection, which means that changes in the DOM are reflected in the collection. For example, Node.childNodes
is live:
var parent = document.getElementById('parent'); var child_nodes = parent.childNodes; console.log(child_nodes.length); // let's assume "2" parent.appendChild(document.createElement('div')); console.log(child_nodes.length); // should output "3"
In other cases, the NodeList
is a static collection, meaning any subsequent change in the DOM does not affect the content of the collection. document.querySelectorAll
returns a static NodeList.
It's good to keep this distinction in mind when you choose how to iterate over the items in the NodeList, and how you cache the length of the list in particular.
Why is NodeList
not an Array?
NodeList
are used very much like arrays and it's tempting to invoke Array.prototype
methods on them, however NodeList
objects don't have any of the familiar Array methods.
JavaScript has an inheritance mechanism based on prototypes for both built–in objects (like Arrays) and host objects (like NodeLists). Array instances inherit array methods (such as forEach
or map
) because their prototype chain looks like the following:
myArray --> Array.prototype --> Object.prototype --> null
(The prototype chain of an object can be obtained by calling Object.getPrototypeOf
several times.)
forEach
, map
and the likes are own properties of the Array.prototype
object.
Unlike arrays, NodeList
prototype chain looks like the following:
myNodeList --> NodeList.prototype --> Object.prototype --> null
NodeList.prototype
contains the item
method, but none of the Array.prototype
methods, so they cannot be used on NodeLists.
Workarounds
One idea would be to add Array.prototype
methods to NodeList.prototype
. However, be aware that Extending the DOM is dangerous, especially in old version of Internet Explorer (6, 7, 8).
var arrayMethods = Object.getOwnPropertyNames( Array.prototype ); arrayMethods.forEach( attachArrayMethodsToNodeList ); function attachArrayMethodsToNodeList(methodName) { if(methodName !== "length") { NodeList.prototype[methodName] = Array.prototype[methodName]; } }; var divs = document.getElementsByTagName( 'div' ); var firstDiv = divs[ 0 ]; firstDiv.childNodes.forEach(function( divChild ){ divChild.parentNode.style.color = '#0F0'; });
Another approach without extending the DOM:
var divs = document.getElementsByTagName( 'div' ); var firstDiv = divs[ 0 ]; Array.prototype.forEach.call(firstDiv.childNodes, function( divChild ){ divChild.parentNode.style.color = '#0F0'; });
Note that in the above, passing a host object (like a NodeList) as this
to a native method (such as forEach
) is not guaranteed to work in all browsers and is known to fail in some.
Example
It's possible to loop over the items in a NodeList
using:
for (var i = 0; i < myNodeList.length; ++i) { var item = myNodeList[i]; // Calling myNodeList.item(i) isn't necessary in JavaScript }
Don't be tempted to use for...in
or for each...in
to enumerate the items in the list, since that will also enumerate the length and item properties of the NodeList
and cause errors if your script assumes it only has to deal with element
objects. Also, for..in
is not guaranteed to visit the properties in any particular order.
for...of
loops will loop over NodeList objects correctly, in browsers that support for...of
(like Firefox 13 and later):
var list = document.querySelectorAll( 'input[type=checkbox]' ); for (var item of list) { item.checked = true; }
Converting a NodeList to an Array
Sometimes it's more convenient to work with the content of a NodeList using familiar Array methods. Here is a technique for converting a NodeList object to an Array:
var div_list = document.querySelectorAll('div'); // returns NodeList var div_array = Array.prototype.slice.call(div_list); // converts NodeList to Array
It's also possible to use the more recent Spread operator, in browsers that support this feature:
var div_list = document.querySelectorAll('div'); // returns NodeList var div_array = [...div_list]; // converts NodeList to Array
Conversion can also be done using Array.from() method:
var div_list = document.querySelectorAll('div'); // returns NodeList var div_array = Array.from(div_list); // converts NodeList to Array
Specification
Specifications
Specification | Status | Comment |
---|---|---|
DOM The definition of 'NodeList' in that specification. |
Living Standard | |
DOM4 The definition of 'NodeList' in that specification. |
Working Draft | |
Document Object Model (DOM) Level 3 Core Specification The definition of 'NodeList' in that specification. |
Recommendation | |
Document Object Model (DOM) Level 2 Core Specification The definition of 'NodeList' in that specification. |
Recommendation | |
Document Object Model (DOM) Level 1 Specification The definition of 'NodeList' in that specification. |
Recommendation | Initial definition. |