JavaScriptで、NodeListを配列に変換する最良の方法は何ですか?


84

DOMメソッドdocument.querySelectorAll()(および他のいくつかのメソッド)はを返しますNodeList

リストを操作するには、たとえばを使用してforEach()NodeList最初にに変換する必要がありArrayます。

変換するための最良の方法何NodeListにはArray


1
querySelectorAll()の戻り値は、技術的にはNodeListと呼ばれていると思います。
jfriend00 2011

mdmから "elementList = document.querySelectorAll(selectors);"
cc young

1
elementListは変数名です。その同じページで、戻り値の型がNodeListである方法について説明しています。
jfriend00 2011

補正のためのおかげで-質問に固定
ccの若い

回答:


70

ES6を使用すると、次のことが簡単にできます。

const spanList = [...document.querySelectorAll("span")];

1
これは私に与えますType 'NodeListOf<Element>' must have a '[Symbol.iterator]()' method that returns an iterator.ts(2488)
コールバック

こんにちは@callback、これはTypeScript関連のエラーのようです。tsconfigファイルのlib配列に「es6」を追加せずにes6コンパイルをターゲットにすることを選択した可能性があります。よろしく
Freezystem

1
こんにちは@Freezystem、あなたは正しいです!es2015をターゲットにしています。ありがとう!
コールバック

ES6とES2015 @Callback同じものです
DarkNeuron

66

ES6ではを使用できますArray.from(myNodeList)。次に、お気に入りの配列メソッドを使用します。

var myNodeList = document.querySelectorAll('.my-selector');

// ALT 1
Array.from(myNodeList).forEach(function(el) {
  console.log(el);
});

ES6シムを使用して、古いブラウザーでもこれを機能させます。


トランスパイラー(Babelなど)を使用している場合は、さらに2つの選択肢があります。

var myNodeList = document.querySelectorAll('.my-selector');

// ALT 2
for (var el of myNodeList) {
  el.classList.add('active'); // or some other action
}

// ALT 3
[...myNodeList].forEach((el) => {
  console.log(el);
});

nodeListがイテレータを提供するというes6の下でも真実ではありませんか?
cc young

4
@ccyoungですが、Symbolオブジェクトをシムできないため、非準拠のES6ブラウザーではイテレーターは機能しません。シムできるため、使用することをお勧めしますArray.from(myNodeList)
roc 2016年

したがって、Array.from(el.childNodes)が最初のノードを配列の一部として返さないというこの問題があります。
zinoadidi

49

プロトタイプのsliceメソッドを使用して、配列に変換できますArray

var elList = document.querySelectorAll('.viewcount');
elList = Array.prototype.slice.call(elList, 0);

Furthermore, if all you need is forEach, you can invoke that from the Array prototype, without coercing it to an array first:

var elList = document.querySelectorAll('.viewcount');
Array.prototype.forEach.call(elList, function(el) {
    console.log(el);
});

In ES6, you can use the new Array.from function to convert it to an array:

Array.from(elList).forEach(function(el) {
    console.log(el);
});

This is currently only in bleeding edge browsers, but if you're using a polyfill service you will have access to this function across the board.


If you're using an ES6 transpiler, you can even use a for..of loop instead:

for (var element of document.querySelectorAll('.some .elements')) {
  // use element here
}

thanks. under newer javascript thought/hoping there was a more succinct coercion.
cc young

6
@cc young - Do note, the reason I'm using Array.prototype.forEach instead of [].forEach, is because the latter creates a new Array object, which is totally unnecessary.
Joseph Silber

@JosephSilber ahh thank you - that is the new array that's created is the empty []? My thinking is that it would get garbage collected and the memory impact is negligible, can anyone comment on this?
Daniel Sokolowski

@Daniel this is true, but there's still the computation of creating and destroying the array.
Brett

21

Why convert? - just call function of Array directly on element collection ;)

[].forEach.call( $('a'), function( v, i) {
    // do something
});

assuming $ is your alias for querySelectorAll, of course


edit: ES6 allows for even shorter syntax [...$('a')] (works in Firefox only, as of May 2014)


Assuming $ is querySelectorAll.
c69

3
Your answer implies jQuery usage. If that's the case, this tomfoolery is completely unnecessary, thanks to .each().
Matt Ball

1
lol, why ? nothing forbids you from making aliases like function $ ( s ) { return document.querySelectorAll(s); }.
c69

5
If you're going to use jQuery, then the more succint solution is: $('a').each(function(i, v) {...});
jfriend00

2
offtopic: EcmaScript 5 is a standard for a year already, all current-generation browsers support the new methods of Arrays, and question was specificly about using those methods on NodeList aka Element collection.
c69

10

2020 update: nodeList.forEach() is now an official standard and supported in all current browsers.

Older browsers can use the polyfill below.

To operate on the list in javascript, e.g. using forEach(), the NodeList must be converted to an Array.

That's not true. .forEach() works in current browsers. If it's missing, you can use a polyfill to add .forEach() from Array to NodeList and it works fine:

if ( ! NodeList.prototype.forEach ) {
  NodeList.prototype.forEach = Array.prototype.forEach;
}

You can now run:

myNodeList.forEach(function(node){...})

To iterate over NodeLists just like Arrays.

This produces much shorter and cleaner code than .call() everywhere.


1
This answer was exactly what I needed and these 3 lines saved a lot of time. All the other answers would have required changing a bunch of code and I'm not understanding why.
Scribblemacher

downvotes were probably because monkey patching built-in prototypes is considered bad practice
DuBistKomisch

@DuBistKomisch This is a polyfill, only applied if the standard NodeList.foreach() doesn't exist.
mikemaccana

2
ah my bad, didn't realise they actually added forEach specifically, I came here looking for filter
DuBistKomisch

@DuBistKomisch you can use the same technique for filter, but you may wish to give it an unofficial name NodeList.prototype.dbkFilter or similar if you're worried about a future standard using a different implementation .
mikemaccana

9

Does it have to be forEach? You could simply use a for loop to iterate over the list:

for (var i = 0; i < elementList.length; i++) {
    doSomethingWith(elementlist.item(i));
}

1
+1 for going with the simple solution that doesn't add unnecessary array conversions. FYI, Instead of elementList.item(i), you could just use elementList[i].
jfriend00

4
personally I find forEach() a better programming style and less verbose - ymmv
cc young

@cc young: Actually, I agree with you. Except in cases like this, where I would need to run a conversion just so I can use my favorite pattern. That makes it clunky and looks like: "When all you have is a hammer, everything starts to look like a nail."
nfechner

And here is a nuttier way :) for (var oElement, i = 0; oElement = aMenuItemsElements; i++ { console.log(oElement); }
Daniel Sokolowski

Problem here is that you can’t nest another for (var i…) loop because the for loop doesn’t create its own scope (like it does in C/C++ now). And then the i get mixed up.
Jens

2

ES6 allows cool ways like var nodeArray = Array.from(nodeList) but my favorite one is the new spread operator.

var nodeArray = Array(...nodeList);

A perfect solution ! This solution applies for Typescript too.
Nirus

I would like to add that this only works with TypeScript as long as you're not transpiling to ES5 or lower.
Rudey

2

That worked with me in ES6

lets assume you have nodelist like that

<ul>
  <li data-time="5:17">Flexbox video</li>
  <li data-time="8:22">Flexbox video</li>
  <li data-time="3:24">Redux video</li>
  <li data-time="5:17">Flexbox video</li>
  <li data-time="7:17">Flexbox video</li>
  <li data-time="4:17">Flexbox video</li>
  <li data-time="2:17">Redux video</li>
  <li data-time="7:17">Flexbox video</li>
  <li data-time="9:54">Flexbox video</li>
  <li data-time="5:53">Flexbox video</li>
  <li data-time="7:32">Flexbox video</li>
  <li data-time="2:47">Redux video</li>
  <li data-time="9:17">Flexbox video</li>

</ul>


const items = Array.from(document.querySelectorAll('[data-time]'));

console.log(items);

2

I use the following because I think it's easiest to read:

const elements = document.getElementsByClassName('element');
[...elements].forEach((element) => {
   // code
});


2

Well, this works for me too:

const elements = Object.values( document.querySelector(your selector here) )

Object.values() returns Array of values of given object. NodeList is object, as is everything in JS.

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/values

But it's not compatible with IE, so i guess Array.prototype.*array_method*.call(yourNodeList) is the best option. With this you can invoke any array method on your NodeList


弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.