Fastest way to convert JavaScript NodeList to Array?

JavascriptArraysNodelist

Javascript Problem Overview


Previously answered questions here said that this was the fastest way:

//nl is a NodeList
var arr = Array.prototype.slice.call(nl);

In benchmarking on my browser I have found that it is more than 3 times slower than this:

var arr = [];
for(var i = 0, n; n = nl[i]; ++i) arr.push(n);

They both produce the same output, but I find it hard to believe that my second version is the fastest possible way, especially since people have said otherwise here.

Is this a quirk in my browser (Chromium 6)? Or is there a faster way?

EDIT: For anyone who cares, I settled on the following (which seems to be the fastest in every browser that I tested):

//nl is a NodeList
var l = []; // Will hold the array of Node's
for(var i = 0, ll = nl.length; i != ll; l.push(nl[i++]));

EDIT2: I found an even faster way

// nl is the nodelist
var arr = [];
for(var i = nl.length; i--; arr.unshift(nl[i]));

Javascript Solutions


Solution 1 - Javascript

With ES6, we now have a simple way to create an Array from a NodeList: the Array.from() function.

// nl is a NodeList
let myArray = Array.from(nl)

Solution 2 - Javascript

2021 update: nodeList.forEach() is now standard and supported in all current browsers (around 95% on both desktop & mobile).

So you can simply do:

document.querySelectorAll('img').forEach(highlight);

Other cases

If you for some reason want to convert it to an array, not just iterate over it - which is a completely relevant use-case - you can use [...destructuring] or Array.from since ES6

let array1 = [...mySetOfElements];
// or
let array2 = Array.from(mySetOfElements);

This also works for other array-like structures that aren't NodeLists

  • HTMLCollection returned by e.g. document.getElementsByTagName
  • objects with a length property and indexed elements
  • iterable objects (objects such as Map and Set)



Outdated 2010 Answer

The second one tends to be faster in some browsers, but the main point is that you have to use it because the first one is just not cross-browser. Even though The Times They Are a-Changin'

@kangax (IE 9 preview)

> Array.prototype.slice can now convert > certain host objects (e.g. NodeList’s) > to arrays — something that majority of > modern browsers have been able to do > for quite a while.

Example:

Array.prototype.slice.call(document.childNodes);

Solution 3 - Javascript

Here's a new cool way to do it using the ES6 spread operator:

let arr = [...nl];

Solution 4 - Javascript

In ES6 you can either use:

  • Array.from

    let array = Array.from(nodelist)

  • Spread operator

    let array = [...nodelist]

Solution 5 - Javascript

Some optimizations:

  • save the NodeList's length in a variable
  • explicitly set the new array's length before setting.
  • access the indices, rather than pushing or unshifting.

Code (jsPerf):

var arr = [];
for (var i = 0, ref = arr.length = nl.length; i < ref; i++) {
 arr[i] = nl[i];
}

Solution 6 - Javascript

The results will completely depend on the browser, to give an objective verdict, we have to make some performance tests, here are some results, you can run them here:

Chrome 6:

https://chart.apis.google.com/chart?chtt=NodeList%20to%20Array%7COps/sec%20%28Chrome%206.0.453.1%20on%20Windows%20NT%29&chts=000000,10&cht=bhg&chd=t:3632,3994,3652&chds=0,3994&chxt=x&chxl=0:|0|4K&chsp=0,1&chm=tArray.prototype.slice.call%283.6K%29,000000,0,0,10|tfor%20loop%284K%29,000000,0,1,10|treverse%20while%20loop%283.7K%29,000000,0,2,10&chbh=15,0,5&chs=250x130"/>

Firefox 3.6:

https://chart.apis.google.com/chart?chtt=NodeList%20to%20Array%7COps/sec%20%28Firefox%203.6.3%20on%20Windows%20NT%29&chts=000000,10&cht=bhg&chd=t:1037,1333,1065&chds=0,1333&chxt=x&chxl=0:|0|1.3K&chsp=0,1&chm=tArray.prototype.slice.call%281K%29,000000,0,0,10|tfor%20loop%281.3K%29,000000,0,1,10|treverse%20while%20loop%281.1K%29,000000,0,2,10&chbh=15,0,5&chs=250x130"/>

Firefox 4.0b2:

https://chart.apis.google.com/chart?chtt=NodeList%20to%20Array%7COps/sec%20%28unknown%20platform%29&chts=000000,10&cht=bhg&chd=t:1349,2278,1096&chds=0,2278&chxt=x&chxl=0:|0|2.3K&chsp=0,1&chm=tArray.prototype.slice.call%281.3K%29,000000,0,0,10|tfor%20loop%282.3K%29,000000,0,1,10|treverse%20while%20loop%281.1K%29,000000,0,2,10&chbh=15,0,5&chs=250x130" />

Safari 5:

https://chart.apis.google.com/chart?chtt=NodeList%20to%20Array%7COps/sec%20%28Safari%205.0%20on%20Windows%20NT%29&chts=000000,10&cht=bhg&chd=t:4881,3418,4281&chds=0,4881&chxt=x&chxl=0:|0|4.9K&chsp=0,1&chm=tArray.prototype.slice.call%284.9K%29,000000,0,0,10|tfor%20loop%283.4K%29,000000,0,1,10|treverse%20while%20loop%284.3K%29,000000,0,2,10&chbh=15,0,5&chs=250x130"/>

IE9 Platform Preview 3:

https://chart.apis.google.com/chart?chtt=NodeList%20to%20Array%7COps/sec%20%28MSIE%209.0%20on%20Windows%20NT%29&chts=000000,10&cht=bhg&chd=t:373,304,379&chds=0,379&chxt=x&chxl=0:|0|379&chsp=0,1&chm=tArray.prototype.slice.call%28373%29,000000,0,0,10|tfor%20loop%28304%29,000000,0,1,10|treverse%20while%20loop%28379%29,000000,0,2,10&chbh=15,0,5&chs=250x130" />

Solution 7 - Javascript

The most fast and cross browser is

for(var i=-1,l=nl.length;++i!==l;arr[i]=nl[i]);

As I compared in

http://jsbin.com/oqeda/98/edit

*Thanks @CMS for the idea!

Chromium (Similar to Google Chrome) Firefox Opera

Solution 8 - Javascript

Assuming nodeList = document.querySelectorAll("div"), this is a concise form of converting nodelist to array.

var nodeArray = [].slice.call(nodeList);

See me use it here.

Solution 9 - Javascript

NodeList.prototype.forEach = Array.prototype.forEach;

Now you can do document.querySelectorAll('div').forEach(function()...)

Solution 10 - Javascript

faster and shorter :

// nl is the nodelist
var a=[], l=nl.length>>>0;
for( ; l--; a[l]=nl[l] );

Solution 11 - Javascript

Check out this blog post here that talks about the same thing. From what I gather, the extra time might have to do with walking up the scope chain.

Solution 12 - Javascript

This is the function I use in my JS:

function toArray(nl) {
	for(var a=[], l=nl.length; l--; a[l]=nl[l]);
	return a;
}

Solution 13 - Javascript

Here are charts updated as of the date of this posting ("unknown platform" chart is Internet Explorer 11.15.16299.0):

Safari 11.1.2 Firefox 61.0 Chrome 68.0.3440.75 Internet Explorer 11.15.16299.0

From these results, it seems that the preallocate 1 method is the safest cross-browser bet.

Solution 14 - Javascript

just do it vat arr = [...nodeList]

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
Questionjairajs89View Question on Stackoverflow
Solution 1 - JavascriptwebdifView Answer on Stackoverflow
Solution 2 - JavascriptgblazexView Answer on Stackoverflow
Solution 3 - JavascriptAlexander OlssonView Answer on Stackoverflow
Solution 4 - JavascriptIsabellaView Answer on Stackoverflow
Solution 5 - JavascriptThaiView Answer on Stackoverflow
Solution 6 - JavascriptChristian C. SalvadóView Answer on Stackoverflow
Solution 7 - JavascriptFelipe BuccioniView Answer on Stackoverflow
Solution 8 - JavascriptUdo E.View Answer on Stackoverflow
Solution 9 - JavascriptJohn WilliamsView Answer on Stackoverflow
Solution 10 - JavascriptanonymousView Answer on Stackoverflow
Solution 11 - JavascriptVivin PaliathView Answer on Stackoverflow
Solution 12 - JavascriptWeb_DesignerView Answer on Stackoverflow
Solution 13 - JavascriptTomSlickView Answer on Stackoverflow
Solution 14 - Javascriptsubhajit dasView Answer on Stackoverflow