[javascript] Fastest way to convert JavaScript NodeList to Array?

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]));

This question is related to javascript arrays nodelist

The answer is


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:

Firefox 3.6:

Firefox 4.0b2:

Safari 5:

IE9 Platform Preview 3:


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];
}

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.


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;
}

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

let arr = [...nl];

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.


faster and shorter :

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

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

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


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)

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


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.


In ES6 you can either use:

  • Array.from

    let array = Array.from(nodelist)

  • Spread operator

    let array = [...nodelist]