NodeList
オブジェクトは {{domxref("Node.childNodes")}} や {{domxref("document.querySelectorAll")}} などのメソッドから返されるノードのコレクションを表します。
プロパティ
length
- NodeList に含まれるノードの数
メソッド
item ( idx )
- インデックスで指定した要素、もしくはインデックスが範囲外の場合は
null
を返します。範囲外の場合にundefined
を返すnodeList[idx]
の代わりにこのメソッドを使うことができます。
説明
生きたコレクションとしての側面
NodeList
は DOM の変化を反映する、生きたコレクションになっていることがあります。 {{domxref("Node.childNodes")}} もその一つです。
var parent = document.getElementById('parent'); var child_nodes = parent.childNodes; console.log(child_nodes.length); // "2" だったものが parent.appendChild(document.createElement('div')); console.log(child_nodes.length); // "3" になる
一方で、DOM の変化を一切反映しない静的なコレクションになっていることもあります。例えば {{domxref("document.querySelectorAll")}} は静的な NodeList を返します。
NodeList の要素を列挙したり、要素の数をキャッシュするときには、この違いに注意した方がよいでしょう。
なぜ NodeList
は Array ではないのか
NodeList
は配列と似た使い方をすることが多く、 Array.prototype
のメソッドを使いたくなりますが、 NodeList
はおなじみの Array メソッドを一切備えていません。
JavaScript は Array などのビルトインオブジェクトと NodeLIst などのホストオブジェクトのどちらにもプロトタイプベースの継承メカニズムを使います。 Array のインスタンスが forEach
や map
などのメソッドを備えているのは、以下のようなプロトタイプチェーンになっているからです。
myArray --> Array.prototype --> Object.prototype --> null
(オブジェクトのプロトタイプチェーンは Object.getPrototypeOf
を繰り返し呼ぶことで調べることができます)
forEach や
map
は Array.prototype
オブジェクト自身が持つプロパティです。
一方 NodeList
のプロトタイプチェーンは次のようになっています。
myNodeList --> NodeList.prototype --> Object.prototype --> null
NodeList.prototype
には item
メソッドがありますが、 Array.prototype
のメソッドは含まれていないため、これらを NodeLists で使うことはできないのです。
回避策
まず、 Array.prototype
のメソッドを NodeList.prototype
に追加する方法があります。ただし DOM の拡張は危険なことであり、特に古い 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'; });
もう一つの方法では DOM を拡張しません。
var forEach = Array.prototype.forEach; var divs = document.getElementsByTagName( 'div' ); var firstDiv = divs[ 0 ]; forEach.call(firstDiv.childNodes, function( divChild ){ divChild.parentNode.style.color = '#0F0'; });
この方法ではホストオブジェクト (NodeList など) を this
としてネイティブメソッド (forEach など
) に渡していますが、全てのブラウザで動くことが保証されているわけではなく、動かないケースもあることが知られています。
例
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; }
NodeList を Array に変換する
NodeList の中身を慣れ親しんだ Array のメソッドで扱いたいこともあるでしょう。こうすると NodeList オブジェクトを Array に変換できます。
var div_list = document.querySelectorAll('div'); // returns NodeList var div_array = Array.prototype.slice.call(div_list); // converts NodeList to Array
Spread operator をサポートするブラウザではこれを使うこともできます。
var div_list = document.querySelectorAll('div'); // returns NodeList var div_array = [...div_list]; // converts NodeList to Array
もしくは Array.from() メソッドを使ってもよいでしょう。
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]); })
仕様
仕様書 | 策定状況 | コメント |
---|---|---|
{{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. |