views:

375

answers:

3

I stumbled onto this neat shortcut for converting a DOM NodeList into a regular array, but I must admit, I don't completely understand how it works:

[].slice.call(document.querySelectorAll('a'), 0)

So it starts with an empty array [], then slice is used to convert the result of call to a new array yeah?

The bit I don't understand is the call. How does that convert document.querySelectorAll('a') from a NodeList to a regular array?

+4  A: 

What's happening here is that you call slice() as if it was a function of NodeList using call(). What slice() does in this case is create an empty array, then iterate through the object it's running on (originally an array, now a NodeList) and keep appending the elements of that object to the empty array it created, which is eventually returned. Here's an article on this.

EDIT:

So it starts with an empty array [], then slice is used to convert the result of call to a new array yeah?

That's not right. [].slice returns a function object. A function object has a function call() which calls the function assigning the first parameter of the call() to this; in other words, making the function think that it's being called from the parameter (the NodeList returned by document.querySelectorAll('a')) rather than from an array.

Max Shawabkeh
Note too here that although this is semantically equivalent to saying `Array.prototype.slice.call(...)`, it actually instantiates an array object (`[]`) only to access its prototype slice method. That is a wasted instantiation. Saying `Array.prototype.slice.call(...)` instead is cleaner, although you add several characters to your JS if you're counting...
quixoto
+1  A: 

What this does is retrieve the slice function from an Array. It then calls that function, but using the result of document.querySelectorAll as the this object instead of an actual array.

Brian Campbell
A: 

In javascript, methods of an object can be bound to another object at runtime. In short, javascript allows an object to "borrow" the method of another object:

object1 = {
    name:'frank',
    greet:function(){
        alert('hello '+this.name)
    }
};

object2 = {
    name:'andy'
};

// Note that object2 has no greet method.
// But we may "borrow" from object1:

object1.greet.call(object2);

The call and apply methods of function objects (in javascript functions are objects as well) allows you to do this. So in your code you could say that the Nodelist is borrowing an array's slice method. What does the conversion is the fact that slice returns another array as it's result.

slebetman