Nowadays, we can convert a
NodeList into an array by using the modern
Array.from() method. But this requires a polyfill for IE, so I still use the older
Array.prototype.slice.call() method sometimes. It’s a lot harder to read, though, so let’s dig into how it works!
Normally, you call the
slice() method directly on an array instance. It copies a segment of an array into a brand new array:
As my friend Chris Ferdinandi notes in the Vanilla JS Toolkit:
To create a brand new copy of an array in its entirety, you can use
slice()with no arguments.
This is the important part.
All array instances inherit the
slice() method through their prototype chain. Don’t worry too much about this technical term, but if you’re interested, you can learn more in the MDN Web Docs:
Inheritance and the prototype chain →
call() method is available to all functions via their prototype chain.
(Not just the functions that are available to arrays.)
As explained in the MDN Web Docs:
call()method calls a function with a given
thisvalue and arguments provided individually.
Essentially, binding a different value for
this changes the scope of the function. This lets you call the function on an object to which it would not normally be available.
Putting it all together
Let’s look at the following example:
First, we get all paragraphs on the page using the
querySelectorAll() method. This returns a
As I mentioned above, the
slice() method is only available to array instances. Our
NodeList cannot access it directly.
So we can’t just call
paragraphs.slice() to create a copy of the
NodeList as a brand new array. We’d get a
TypeError if we tried:
Remember that the
call() method allows us to change the scope of a function, so we can call it on an object to which it would not normally be available?
Normally, when you call the
slice() method directly on an array instance, its internal
this value points to that array instance.
But here, we change the
this value so that it points to the
NodeList we have stored in the
This successfully creates a brand new copy of the
NodeList as an array, so all the array instance methods are now available to us!
this keyword and the
Function.prototype.call() method can be really confusing. Even seasoned developers struggle with them.
If you want to learn more, I recommend the following:
- this in the MDN Web Docs
If none of
this makes sense (get it?), seriously, don’t worry about it. You can still use the
Array.prototype.slice.call() trick safely.
If you have questions, feedback, or any other suggestions, please do email me. I'd love to hear from you!