Please note, this is a STATIC archive of website developer.mozilla.org from 03 Nov 2016, cach3.com does not collect or store any user information, there is no "phishing" involved.

Revision 1126861 of NodeList

  • Revision slug: Web/API/NodeList
  • Revision title: NodeList
  • Revision id: 1126861
  • Created:
  • Creator: fscholz
  • Is current revision? No
  • Comment bug 1290636

Revision Content

{{APIRef("DOM")}}

NodeList objects are collections of nodes such as those returned by {{domxref("Node.childNodes")}} and the {{domxref("document.querySelectorAll")}} method.

Properties

{{domxref("NodeList.length")}}
The number of nodes in the NodeList.

Methods

{{domxref("NodeList.item()", "NodeList.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 accessing nodeList[idx] (which instead returns  undefined when idx is out-of-bounds).
{{domxref("NodeList.entries()")}}
Returns an {{jsxref("Iteration_protocols","iterator")}} allowing to go through all key/value pairs contained in this object.
{{domxref("NodeList.forEach()")}}
Executes a provided function once per NodeList element.
{{domxref("NodeList.keys()")}}
Returns an {{jsxref("Iteration_protocols", "iterator")}} allowing to go through all keys of the key/value pairs contained in this object.
{{domxref("NodeList.values()")}}
Returns an {{jsxref("Iteration_protocols", "iterator")}} allowing to go through all values of the key/value pairs contained in this object.

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, {{domxref("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. {{domxref("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 {{domxref("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

Another possibility is to use {{jsxref("Object.keys()")}} and {{jsxref("Array.prototype.forEach()")}} (for which polyfills are available):

var div_list = document.querySelectorAll('div'); // returns NodeList
Object.keys(div_list).forEach(function(key) {
  console.log(div_list[key]);
})

Specifications

Specification Status Comment
{{SpecName('DOM WHATWG', '#interface-nodelist', 'NodeList')}} {{ Spec2('DOM WHATWG') }}  
{{SpecName('DOM4', '#interface-nodelist', 'NodeList')}} {{ Spec2('DOM4') }}  
{{SpecName('DOM3 Core', 'core.html#ID-536297177', 'NodeList')}} {{ Spec2('DOM3 Core') }}  
{{SpecName('DOM2 Core', 'core.html#ID-536297177', 'NodeList')}} {{ Spec2('DOM2 Core') }}  
{{SpecName('DOM1', 'level-one-core.html#ID-536297177', 'NodeList')}} {{ Spec2('DOM1') }} Initial definition.

Revision Source

<div>{{APIRef("DOM")}}</div>

<p><strong><code>NodeList</code></strong> objects are collections of nodes such as those returned by {{domxref("Node.childNodes")}} and the {{domxref("document.querySelectorAll")}} method.</p>

<h2 id="Properties">Properties</h2>

<dl>
 <dt>{{domxref("NodeList.length")}}</dt>
 <dd>The number of nodes in the <code>NodeList</code>.</dd>
</dl>

<h2 id="Methods">Methods</h2>

<dl>
 <dt>{{domxref("NodeList.item()", "NodeList.item(idx)")}}</dt>
 <dd>Returns an item in the list by its index, or <code>null</code> if the index is out-of-bounds; can be used as an alternative to simply accessing <code>nodeList[idx]</code> (which instead returns&nbsp; <code>undefined</code> when <code>idx</code> is out-of-bounds).</dd>
 <dt>{{domxref("NodeList.entries()")}}</dt>
 <dd>Returns an {{jsxref("Iteration_protocols","iterator")}} allowing to go through all key/value pairs contained in this object.</dd>
 <dt>{{domxref("NodeList.forEach()")}}</dt>
 <dd>Executes a provided function once per <code>NodeList</code> element.</dd>
 <dt>{{domxref("NodeList.keys()")}}</dt>
 <dd>Returns an {{jsxref("Iteration_protocols", "iterator")}} allowing to go through all keys of the key/value pairs contained in this object.</dd>
 <dt>{{domxref("NodeList.values()")}}</dt>
 <dd>Returns an {{jsxref("Iteration_protocols", "iterator")}} allowing to go through all values of the key/value pairs contained in this object.</dd>
</dl>

<h2 id="Description">Description</h2>

<h3 id="A_sometimes-live_collection">A sometimes-live collection</h3>

<p>In some cases, the <code>NodeList</code> is a <em>live collection</em>, which means that changes in the DOM are reflected in the collection. For example, {{domxref("Node.childNodes")}} is live:</p>

<pre class="brush: js">
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"
</pre>

<p>In other cases, the <code>NodeList</code> is a <em>static collection, </em>meaning any subsequent change in the DOM does not affect the content of the collection. {{domxref("document.querySelectorAll")}} returns a static <code>NodeList</code>.</p>

<p>It's good to keep this distinction in mind when you choose how to iterate over the items in the <code>NodeList</code>, and how you cache the length of the list in particular.</p>

<h3 id="Why_is_NodeList_not_an_Array">Why is <code>NodeList</code> not an Array?</h3>

<p><code>NodeList</code> are used very much like arrays and it's tempting to invoke <code>Array.prototype</code> methods on them, however <code>NodeList</code> objects don't have any of the familiar Array methods.</p>

<p>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 <code>forEach</code> or <code>map</code>) because their prototype chain looks like the following:</p>

<p><code>myArray --&gt; Array.prototype --&gt; Object.prototype --&gt; null</code> (The prototype chain of an object can be obtained by calling <code>Object.getPrototypeOf</code> several times.)</p>

<p><code>forEach</code>, <code>map</code> and the likes are own properties of the <code>Array.prototype</code> object.</p>

<p>Unlike arrays, <code>NodeList</code> prototype chain looks like the following:</p>

<p><code>myNodeList --&gt; NodeList.prototype --&gt; Object.prototype --&gt; null</code></p>

<p><code>NodeList.prototype</code> contains the <code>item</code> method, but none of the <code>Array.prototype</code> methods, so they cannot be used on NodeLists.</p>

<h4 id="Workarounds">Workarounds</h4>

<p>One idea would be to add <code>Array.prototype</code> methods to <code>NodeList.prototype</code>. However, be aware that <a href="https://perfectionkills.com/whats-wrong-with-extending-the-dom/">Extending the DOM is dangerous, especially in old version of Internet Explorer (6, 7, 8)</a>.</p>

<pre class="brush: js">
var arrayMethods = Object.getOwnPropertyNames( Array.prototype );

arrayMethods.forEach( attachArrayMethodsToNodeList );

function attachArrayMethodsToNodeList(methodName)
{
  if(methodName !== "length") {
    NodeList.prototype[methodName] = Array.prototype[methodName];
  }
};
&nbsp;
var divs = document.getElementsByTagName( 'div' );
var firstDiv = divs[ 0 ];

firstDiv.childNodes.forEach(function( divChild ){
&nbsp; divChild.parentNode.style.color = '#0F0';
});</pre>

<p>Another approach without extending the DOM:</p>

<pre class="brush: js">
var divs = document.getElementsByTagName( 'div' );
var firstDiv = divs[ 0 ];

Array.prototype.forEach.call(firstDiv.childNodes, function( divChild ){
&nbsp; divChild.parentNode.style.color = '#0F0';
});
</pre>

<div class="note">
<p>Note that in the above, passing a host object (like a NodeList) as <code>this</code> to a native method (such as <code>forEach</code>) is not guaranteed to work in all browsers and is known to fail in some.</p>
</div>

<h2 id="Example">Example</h2>

<p>It's possible to loop over the items in a <code>NodeList</code> using:</p>

<pre class="brush: js">
for (var i = 0; i &lt; myNodeList.length; ++i) {
  var item = myNodeList[i];  // Calling myNodeList.item(i) isn't necessary in JavaScript
}
</pre>

<p>Don't be tempted to use <code><a href="/en-US/docs/JavaScript/Reference/Statements/for...in" title="JavaScript/ Reference/Statements/for...in">for...in</a></code> or <code><a href="/en-US/docs/JavaScript/Reference/Statements/for_each...in" title="JavaScript/ Reference/Statements/for each...in">for each...in</a></code> to enumerate the items in the list, since that will also enumerate the length and item properties of the <code>NodeList</code> and cause errors if your script assumes it only has to deal with {{domxref("element")}} objects. Also, <code>for..in</code> is not guaranteed to visit the properties in any particular order.</p>

<p><code><a href="/en-US/docs/JavaScript/Reference/Statements/for...of" title="/en-US/docs/JavaScript/Reference/Statements/for...of">for...of</a></code> loops will loop over <code>NodeList</code> objects correctly, in browsers that support <code>for...of </code>(like Firefox 13 and later):</p>

<pre class="brush: js">
var list = document.querySelectorAll( 'input[type=checkbox]' );
for (var item of list) {
  item.checked = true;
}</pre>

<h2 id="Converting_a_NodeList_to_an_Array">Converting a NodeList to an Array</h2>

<p>Sometimes it's more convenient to work with the content of a <code>NodeList</code> using familiar Array methods. Here is a technique for converting a NodeList object to an Array:</p>

<pre class="brush: js">
var div_list = document.querySelectorAll('div'); // returns NodeList
var div_array = Array.prototype.slice.call(div_list); // converts NodeList to Array</pre>

<p>It's also possible to use the more recent <a href="/Web/JavaScript/Reference/Operators/Spread_operator" title="JavaScript/ Reference/Operators/Spread_operator">Spread operator</a>, in browsers that support this feature:</p>

<pre class="brush: js">
var div_list = document.querySelectorAll('div'); // returns NodeList
var div_array = [...div_list]; // converts NodeList to Array</pre>

<p>Conversion can also be done using <a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/from">Array.from()</a> method:</p>

<pre class="brush: js">
var div_list = document.querySelectorAll('div'); // returns NodeList
var div_array = Array.from(div_list); // converts NodeList to Array</pre>

<p>Another possibility is to use {{jsxref("Object.keys()")}} and {{jsxref("Array.prototype.forEach()")}} (for which polyfills are available):</p>

<pre class="brush: js">
var div_list = document.querySelectorAll('div'); // returns NodeList
Object.keys(div_list).forEach(function(key) {
  console.log(div_list[key]);
})
</pre>

<h2 id="Specifications" name="Specifications">Specifications</h2>

<table class="standard-table">
 <thead>
  <tr>
   <th scope="col">Specification</th>
   <th scope="col">Status</th>
   <th scope="col">Comment</th>
  </tr>
 </thead>
 <tbody>
  <tr>
   <td>{{SpecName('DOM WHATWG', '#interface-nodelist', 'NodeList')}}</td>
   <td>{{ Spec2('DOM WHATWG') }}</td>
   <td>&nbsp;</td>
  </tr>
  <tr>
   <td>{{SpecName('DOM4', '#interface-nodelist', 'NodeList')}}</td>
   <td>{{ Spec2('DOM4') }}</td>
   <td>&nbsp;</td>
  </tr>
  <tr>
   <td>{{SpecName('DOM3 Core', 'core.html#ID-536297177', 'NodeList')}}</td>
   <td>{{ Spec2('DOM3 Core') }}</td>
   <td>&nbsp;</td>
  </tr>
  <tr>
   <td>{{SpecName('DOM2 Core', 'core.html#ID-536297177', 'NodeList')}}</td>
   <td>{{ Spec2('DOM2 Core') }}</td>
   <td>&nbsp;</td>
  </tr>
  <tr>
   <td>{{SpecName('DOM1', 'level-one-core.html#ID-536297177', 'NodeList')}}</td>
   <td>{{ Spec2('DOM1') }}</td>
   <td>Initial definition.</td>
  </tr>
 </tbody>
</table>
Revert to this revision