Convert NodeList to Array

By  on  

Now that most browsers have implemented querySelectorAll, the native selectorEngine, many framework-dependent developers are getting a rude awakening when dealing with the result of QSA calls:  the NodeList object.  NodeLists are array-like but don't feature many of the methods provided by the Array, like forEach, map, filter, etc.  JavaScript does, however, provide a very simple way to convert NodeLists to Arrays:

var nodesArray = Array.prototype.slice.call(document.querySelectorAll("div"));

The result of the code above is a true Array object containing all of the nodes returned by the QSA.  You could even make the code shorter with this alternative:

var nodesArray = [].slice.call(document.querySelectorAll("div"));

Both snippets will give you an Array for which you can iterate over and do all those other awesome array things!

Recent Features

  • By
    Camera and Video Control with HTML5

    Client-side APIs on mobile and desktop devices are quickly providing the same APIs.  Of course our mobile devices got access to some of these APIs first, but those APIs are slowly making their way to the desktop.  One of those APIs is the getUserMedia API...

  • By
    Being a Dev Dad

    I get asked loads of questions every day but I'm always surprised that they're rarely questions about code or even tech -- many of the questions I get are more about non-dev stuff like what my office is like, what software I use, and oftentimes...

Incredible Demos

  • By
    Display Images as Grayscale with CSS Filters

    CSS filters aren't yet widely supported but they are indeed impressive and a modern need for web imagery.  CSS filters allow you to modify the display of images in a variety of ways, one of those ways being displaying images as grayscale. Doing so requires the...

  • By
    CSS @supports

    Feature detection via JavaScript is a client side best practice and for all the right reasons, but unfortunately that same functionality hasn't been available within CSS.  What we end up doing is repeating the same properties multiple times with each browser prefix.  Yuck.  Another thing we...

Discussion

  1. Matthew Robb

    David does the second example not create a new object allocation that would require being garbage collected? I’d say it’s only a good method for start-up tasks but nothing that is running often, running in a loop or animation.

  2. Hmm… Time to use stuff like underscore js perhaps?

    Also, you can really simply iterate over a node list with native JS anyways.

    var nodes = document.querySelectorAll('div')
      , i
      , node;
    
    for (i in nodes) {
      node = nodes[i];
      console.log(node);
    }
    

    Or, as per my suggestion, use some underscore:

    _.each(document.querySelectorAll('div'), function bringMeThatDiv (div) {
      console.log(div);
    });
    
    • MaxArt

      It’s never a good idea to use for...in to cycle through indexed collections. It’s way slower than the classic for:

      for (var i = 0, n = nodes.length; i < n; i++) {
      ...
      }

      But the whole point of having an Array instead of a NodeList is to get all those goodies like map and forEach, as stated in the post. Callbacks are slow, but if you care about performances, then don't use for…in.

  3. Yaroslaff Fedin

    Doesnt work on old IEs. Though it’s less and less relevant

    • IE8 still will be relevant for the next couple of years.

  4. Jesse

    Is there a difference in performance using this vs Array.prototype.slice.call(nodelist)

    It seems the latter would be slightly more performant, as I thought an array literal allocated memory, and the above doesn’t.

    • MaxArt

      Yes, indeed, using Array.prototype is slightly faster… but takes longer to type!
      It’s just that. A good garbage collector will free the memory right after the statement.
      If performances aren’t vital, you can go for [].

    • Vasu

      Why are we using Array.prototype.slice……. And not simply Array.slice…?

    • tj

      Because it doesn’t work that way?

    • Kyle

      In my opinion, using a raw [] un-intuitive and code-smelly. It doesn’t clearly communicate the intent of the code unless the developer reading it happens to have read a blog post saying “Hey, typing [] is shorter than typing Array.prototype”. And since when is shorter superior? I don’t think you should sacrifice any semantic meaning for the sake of wiggling your fingers a little less. The time you save by typing [] is completely insignificant compared to the potential time you make the next person waste trying to figure out your cool shortcuts.

      Array.prototype.slice preserves the meaning of the code and it’s google-able. And if you really are a slow typist, how about const slice = Array.prototype.slice;? How often are you really typing this, anyways?

  5. If you’re curious about performance have a look at the jsperf test Convert Nodelist to Array

  6. plugnburn

    Here’s the compact code (102 bytes) that allows not only a global , but also a local QSA (to find all the descendants of a certain element)

    Element.prototype._=_=function(s){return[].slice.call((this==self?document:this).querySelectorAll(s))}
  7. Reece

    Note: I tried to use [].concat just like [].slice which will work appropriately with arrays but not a NodeList. [].concat concats the elements of the passed array and does not create another dimension in the returned array which is what I was getting with a NodeList and was causing my error. So do not confuse NodeLists with Arrays.

  8. With Babel, life gets even a bit easier:

    const buttons = document.querySelectorAll('button');
    [...buttons].forEach(initButton);
    

    or for single use stuff, inline all the stuffs:

    [...document.querySelectorAll('button')].forEach(initButton);
    
    • Diego Barahona

      This probably works on Babel, but please don’t do that or advice others to do that. NodeList doesn’t have the Iterator symbol, and thus it can’t work with the standard. If you run your code in latest Chrome for example, it will throw an error of

      document.querySelectorAll(...)[Symbol.iterator] is not a function

      . The fact that it works on Babel, doesn’t mean it is correct.

  9. Jim

    [...document.querySelectorAll("button")] works perfectly for me in chrome

  10. Beginner

    How to get the value of this array? Since I follow yours what I get is the object instead of value.

  11. Rene

    Why not just use ES6?

    let products = Array.from(document.querySelectorAll('.product'));
    
  12. Gil Nimer

    Why not use Array.apply?

    Array.apply([], document.querySelectorAll('div'));
    //or
    Array.apply(null, document.querySelectorAll('div'));
    

Wrap your code in <pre class="{language}"></pre> tags, link to a GitHub gist, JSFiddle fiddle, or CodePen pen to embed!