DOMノードリストをJavaScriptの配列に変換する方法は?


96

HTMLノードのリストを受け入れるJavascript関数がありますが、Javascript配列が期待され(その上でいくつかのArrayメソッドが実行さDocument.getElementsByTagNameれます)、DOMノードリストを返す出力をフィードします。

最初、私は次のような簡単なものを使用することを考えました:

Array.prototype.slice.call(list,0)

そして、それはすべてのブラウザで正常に動作しますが、もちろんInternet Explorerは "JScriptオブジェクトが必要です"というエラーを返します。 Document.getElement*メソッド関数呼び出しのターゲットとして十分なJScriptオブジェクトではないため、正常に機能します。

警告:Internet Explorer固有のコードを書いてもかまいませんが、サードパーティのWebサイトに埋め込むウィジェットを作成しているため、JQueryなどのJavaScriptライブラリを使用することはできません。クライアントの競合が発生します。

私の最後の溝は、DOMノードリストを反復処理して自分で配列を作成することですが、それを行うためのより良い方法はありますか?


さらに良いのは、DOMノードリストから変換する関数を作成することですが、それが本当に私の解決策になると思います。
Kristoffer Sall-Storgaard 2010

> for(i = 0; i< x.length; i ++)反復ごとにNodeListの長さを取得する理由 これは時間の無駄であるだけでなく、NodeListはライブコレクションであるため、ループの本体に長さが変更されると、無限にループしたり、範囲外のインデックスにヒットしたりする可能性があります。後者は、変数に長さを割り当てる場合に発生する可能性がある最悪の事態であり、エラーはエンドレスループよりもはるかに優れています。

これは本当に古い質問ですが、jQueryは特に.noConflictメソッドを使用して構築されたため、他のライブラリ(それ自体も)との競合を引き起こさず、ページに複数のバージョンのjQueryをロードできることを意味します。とはいえ、絶対に必要な場合を除いて、ライブラリの使用/ロードは避けるのが最善です。
vol7ron、2016

@ vol7ron:2016年に早送りしますが、JavaScriptライブラリがページに追加するサイズについては、誰もが緊張しています。確かに、jQueryは縮小され、gzip圧縮されたものは30KBですが、ノードリストを変換するだけではまだ30KBです:-)
Guss

回答:


64

NodeListはホストオブジェクトでありホストオブジェクトでのArray.prototype.sliceメソッドの使用は動作が保証されていません。ECMAScript仕様は次のように述べています。

スライス関数をホストオブジェクトに正常に適用できるかどうかは、実装によって異なります。

を反復してNodeList既存の各要素を配列に追加する単純な関数を作成することをお勧めします。

function toArray(obj) {
  var array = [];
  // iterate backwards ensuring that length is an UInt32
  for (var i = obj.length >>> 0; i--;) { 
    array[i] = obj[i];
  }
  return array;
}

更新:

他の回答が示唆しているように、今では現代の環境でスプレッド構文またはArray.fromメソッドを使用できます。

const array = [ ...nodeList ] // or Array.from(nodeList)

しかし、それについて考えると、NodeListを配列に変換する最も一般的なユースケースはそれを反復処理することであり、NodeList.prototypeオブジェクトにはforEachメソッドがネイティブに含まれているため、最新の環境にいる場合は直接使用するか、ポリフィル。


2
これは、リストの元の順序を逆にした配列を作成しています。これは、OPが必要とするものではないでしょう。array[i] = obj[i]代わりにやるつもりでしたarray.push(obj[i])か?
Tim Down

@ティム、そうだ、以前はそうだったが、昨日の夜に気づかずに編集した(現地時間午前3時)、ありがとう!
CMS

9
どのような状況でobj.length整数値以外の何かになりますか?
ピーター

1
そんなに複雑だなんて信じられない。醜い。これは、Web / JSプログラミングで非常に一般的なニーズです。言語の次のリリースのための新しい方法?
Andrew Koper 2013年

1
@AlbertoPerez、どういたしまして!Saludos hasta Madrid!
CMS

125

ES6次のようにあなただけ使用することができます。

  • スプレッドオペレーター

     var elements = [... nodelist]
  • 使用する Array.from

     var elements = Array.from(nodelist)

https://developer.mozilla.org/en-US/docs/Web/API/NodeListで詳細を参照してください


4
Array.from():Dでとても簡単
Josan Iracheta 2017年

4
誰かがArray.fromTypescriptでこのアプローチを使用している場合(ES5へ)、TSがこれをトランスパイリングするときにのみ機能しますnodelist.slice-これはサポートされていません。
Peter Albert

私はあなたと投票の1年前に同じことを答えましたか?私は...これを説明することはできません
VSYNC

3
@vsync、あなたの答えは言及していませんArray.from
ESR

@EdmundReed-そうですか?それはどのようにそれを正当化しますか。書くのに時間がかかるので、実際の状況では決して使用されることはなく、使用されるだけspreadです。
vsync

16

スプレッド(ES2015)を使用すると、次のように簡単です。[...document.querySelectorAll('p')]

(オプション:Babelを使用して上記のES6コードをES5構文にトランスパイルします)


ブラウザのコンソールで試して、魔法を見てください:

for( links of [...document.links] )
  console.log(links);

少なくとも最新のクローム、44、私はこれを取得します:Uncaught TypeError:document.querySelectorAll is not a function(…)
Nick

@OmidHezaveh-私が言ったように、これはES6コードです。Chrome 44がES6をサポートしているかどうか、サポートしている場合、どの範囲でサポートされているかはわかりません。それはほぼ1年前のブラウザーであり、明らかにこのコードをES6スプレッドをサポートするブラウザーで実行する必要があります。
vsync 2016年

または、実行前にそれをes5にトランスパイルします
HelloWorld

8

この簡単なトリックを使う

<Your array> = [].map.call(<Your dom array>, function(el) {
    return el;
})

これを使用するArray.prototype.slice(または[].sliceそのまま使用する)よりも成功の​​可能性が高いと思う理由を説明していただけますか?注として、Qに記載したIE固有のエラーがIE 8以下で発生し、mapいずれも実装されていないことをコメントしておきます。IE 9(「標準モード」)以上で、両方slicemap同じように成功します。
Guss

6

これは実際には適切なシムではありませんが、DOM要素の操作を必要とする仕様がないためslice()、次のように使用できるようにしています。https//gist.github.com/brettz9/6093105

更新:私がDOM4仕様のエディターでこれを提起したとき(それらがホストオブジェクトに独自の制限を追加するかどうかを尋ねます(そのため、仕様は、配列メソッドで使用されるときにこれらのオブジェクトを正しく変換するために実装者に必要です)、ECMAScript仕様を超えていました実装に依存しないことを許可された)、彼は「ホストオブジェクトは多かれ少なかれES6 / IDLによって時代遅れになっている」と答えました。私は、あたりに見http://www.w3.org/TR/WebIDL/#es-array仕様は、「プラットフォームの配列オブジェクト」を定義するには、このIDLを使用することができますが、http://www.w3.org/TR/domcore/ doesnのの新しいIDLを使用しているようHTMLCollectionようには見えません(Element.attributesDOMStringとDOMTimeStampにWebIDLを使用していることを明示的に示しているだけですが、使用しているように見えます)。なるほど[ArrayClass](これはArray.prototypeから継承されます)が使用されますNodeListNamedNodeMap現在は、それをまだ使用している唯一のアイテムのために非推奨になっていますElement.attributes)。いずれにしても、標準になるようです。ES6 Array.fromは、このような変換を指定するよりも便利で、Array.prototype.slice意味的に明確である[].slice()(そして、Array.slice()私が知る限り、標準的な動作にならない短い形式(「配列ジェネリック」)よりも)。


仕様がこの動作を必要とする方向に進んでいる可能性があることを示すために更新しました。
ブレットザミール2013

5

今日、2018年にはECMAScript 2015(第6版)またはES6を使用できましたが、すべてのブラウザーがそれを理解できるわけではありません(例:IEがすべてを理解するわけではありません)。必要に応じて、次のようにES6を使用できます。 var array = [... NodeList];スプレッド演算子として)またはvar array = Array.from(NodeList);

それ以外の場合(ES6を使用できない場合)、a NodeListをに変換する最短の方法を使用できますArray

var array = [].slice.call(NodeList, 0);

例えば:

var nodeList = document.querySelectorAll('input');
//we use "{}.toString.call(Object).slice(8, -1)" to find the class name of object
console.log({}.toString.call(nodeList).slice(8, -1)); //NodeList

var array = [].slice.call(nodeList, 0);
console.log({}.toString.call(array).slice(8, -1)); //Array

var result = array.filter(function(item){return item.value.length > 5});

for(var i in result)
  console.log(result[i].value); //credit, confidence
<input type="text" value="trust"><br><br>
<input type="text" value="credit"><br><br>
<input type="text" value="confidence">

ただし、DOMノードリストを簡単に繰り返し処理する場合は、a NodeListをに変換する必要はありませんArrayNodeListを使用して項目をループすることは可能です:

var nodeList = document.querySelectorAll('input');
// Calling nodeList.item(i) isn't necessary in JavaScript
for(var i = 0; i < nodeList.length; i++)
    console.log(nodeList[i].value); //trust, credit, confidence
<input type="text" value="trust"><br><br>
<input type="text" value="credit"><br><br>
<input type="text" value="confidence">

リスト内のアイテムを使用しfor...inたりfor each...in列挙したりしないでください。これにより、の長さとアイテムのプロパティも列挙され、NodeListスクリプトが要素オブジェクトのみを処理すればよいと想定した場合にエラーが発生します。また、for..in特定の順序でプロパティを訪問することは保証されていません。for...ofループはNodeListオブジェクトを正しくループします。

も参照してください:


3
var arr = new Array();
var x= ... get your nodes;

for (i=0;i<x.length;i++)
{
  if (x.item(i).nodeType==1)
  {
    arr.push(x.item(i));
  }
}

これは動作し、ブラウザ間ですべての「要素」ノードを取得します。


1
これは基本的に@CMSの回答と同じですが、要素ノードのみが必要であると想定している点が異なります-不要です。
ガス2012
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.