ノードリスト (NodeList)

NodeListオブジェクトは、 Node.childNodesquerySelectorAllメソッド等によって返されるノードのコレクションです。

プロパティ

length
NodeList内のノードの数です。

メソッド

item (idx)
リスト内から指定されたインデックスの項目を返し、範囲外のインデックスであればnullを返します。 後者の未定義である範囲外のidxが提供されるケースを除き、nodeList[idx]として評価されます。

説明

"ライブ"(実稼働中の)コレクション

あるケースで、NodeListは実稼働中のコレクションになります。 これはDOMの変更が、コレクション内に反映されることを意味します。

var divs = document.getElementsByTagName( 'div' );
// divs.length === 2

// 別divを子として追加
document.body.appendChild( document.createElement( 'div' ) );
// divのNodeListは自動的に更新されます。
// ここでは、divs.length === 3 になります。

もし、NodeListがdocument.querySelectorAllの値として返されたものであれば、 それは実稼働中のものではありません

何故、NodeList上でforEachやmapが使えないのでしょうか?

NodeListはまるで配列のように使用されるため、 Array.prototypeのメソッドを使用する衝動に駆られてしまいますが、 それらのメソッドを持ちあわせていません。

JavaScriptは、組み込みオブジェクト(Arrayのような)とホストオブジェクト(NodeListのような)の両方で、 prototypeを基にした継承メカニズムを持ちます。 Arrayインスタンスは、下記のようなprototypeチェーンを持つため、 配列メソッドを(forEachmapのような)継承します。

myArray --> Array.prototype --> Object.prototype --> null
(オブジェクトのprototypeチェーンは、 Object.getPrototypeOfを呼び出すことで取得することが出来ます。)

forEachmap等は、Array.prototypeオブジェクト自身のプロパティです。

配列とは異なり、NodeListのprototypeチェーンは下記のようになります。

myNodeList --> NodeList.prototype --> Object.prototype --> null

NodeList.prototypeitemメソッドを持ちますが、 Array.prototypeのメソッドは持たないため、それらをNodeList上で使用することは出来ません。

ワークアラウンド

1つの解決策として、Array.prototypeのメソッドをNodeList.prototypeに追加する方法があります。 ただし、DOMを拡張することは特に古いバージョンのInternet Explorer(6,7,8)で危険であることに注意してください。

var arrayMethods = Object.getOwnPropertyNames( Array.prototype );

arrayMethods.forEach( attachArrayMethodsToNodeList );

function attachArrayMethodsToNodeList(methodName)
{
    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';
});

上記において、このようにネイティブメソッド(ここではforEach)に渡されるホストオブジェクト(ここではNodeList)は、 全てのブラウザで動作することが保証されない事と、一部で処理が失敗することが知られているため、注意してください。

NodeListを使用して、各項目をループ処理することが可能です。

for (var i = 0; i < myNodeList.length; ++i) {
  // myNodeList.item(i)の呼び出しは、
  // JavaScriptのおいて不可欠というわけではありません。
  // 訳注: item()メソッドは、実際にはあまり使用されていない、
  //       といった意味ではないかと思います。
  var item = myNodeList[i];
}

NodeListのlengthとitemプロパティが数えられることから、 for...in等を使用したくなるかもしれませんが、 もしスクリプトが要素オブジェクトの集まりとしてのみ扱うと判断した場合にエラーが発生します。(翻訳に自信なし) また、for...inは特定の順序で、 プロパティを参照することを保証しません。

var list = document.querySelectorAll( 'input[type=checkbox]' );
for (var item of list) {
  item.checked = true;
}

どのようにNodeListをArrayに変換するのか?

例えば配列(Array)の特定のメソッドを使用するために、時にNodeListオブジェクトから配列への変換が必要となるケースがあります。 下記は、NodeListオブジェクトを配列に変換するテクニックの一例になります。

var turnObjToArray = function(obj) {
  return [].map.call(obj, function(element) {
    return element;
  })
};

var box = document.querySelectorAll('div');
var listBox = turnObjToArray(box)

仕様

 Back to top

© 2017 Mozilla Contributors
Licensed under the Creative Commons Attribution-ShareAlike License v2.5 or later.

このページは、ページトップのURL先のMozilla Developer Network(以下、MDN)のコンテンツを翻訳した内容を基に構成されています。 構成について異なる点も含まれますので、下記の項目を確認し、必要に応じて元のコンテンツをご確認ください。 もし、誤訳などの間違いを見つけましたら、 @tomofまで教えていただければ幸いです。

  • 特定のブラウザに特化しすぎている情報やあまりにも古い情報、 または試験的に導入されているようなAPIや機能については、省略していることがあります。
  • 例やデモについて、実際にページ内で動作させる関係で一部ソースコードを変更している場合や、 その例で使用しているコンテンツの単語や文章などを日本人向けに変更しいてる場合があります。
  • MDNの更新頻度が高いため、元のコンテンツと比べ情報が古くなっている可能性があります。
  • "訳注:"などの断わりを入れた上で、日本人向けの情報の追記を行っている事があります。