46

I was just browsing Sizzle's source code and I came across this line of code:

array = Array.prototype.slice.call( array, 0 );

I looked up what the function is, but I came to the conclusion that it just returns all elements of the array starting from index 0, and puts the whole into the array, i.e. it doesn't really do anything at all.

What is therefore the use of this line of code? What am I missing?

Edit: It's line 863 from https://github.com/jquery/sizzle/blob/master/sizzle.js#L863.

pimvdb
  • 151,816
  • 78
  • 307
  • 352
  • 1
    Seems like a somewhat fangled way of calling `array.slice(0)`, which would make a copy of the array. I don't understand why it's being called in such an impenetrable fashion though. – spender Feb 28 '11 at 17:04
  • 9
    The context makes all the difference. The `array` identifier isn't referencing an actual Array. – user113716 Feb 28 '11 at 17:14

3 Answers3

76

The DOM usually returns a NodeList for most operations like getElementsByTagName.

Although a NodeList almost feels like an array, it is not. It has a length property like an array does, and a method item(index) to access an object at the given index (also accessible with the [index] notation), but that's where the similarity ends.

So to be able to use the wonderful array methods without rewriting them all for a NodeList, the above line is useful.

Another use of converting it to an array is to make the list static. NodeLists are usually live, meaning that if document changes occur, the NodeList object is automatically updated. That could cause problems, if a jQuery object returned to you kept changing right under your nose. Try the following snippet to test the liveness of NodeLists.

var p = document.getElementsByTagName('p');
console.log(p.length); // 2
document.body.appendChild(document.createElement('p'));
// length of p changes as document was modified
console.log(p.length); // 3
Anurag
  • 140,337
  • 36
  • 221
  • 257
  • 4
    Crap this answer drags me a step closer to actually embracing JS. I've been hoping for years it would just go away... +1 to you anyway. – whitneyland Dec 13 '11 at 18:03
  • A question I had that arose from was: how do you know what objects the array methods can be applied to? Apparently, it is any object with a length property, and integer property names (that start from zero?). I also learnt that the “arguments” variable is an array like object, but not an actual array (I did not know). The answer was here: http://stackoverflow.com/questions/7056925/how-does-array-prototype-slice-call-work – zod Feb 27 '12 at 10:08
  • 1
    @zod: If you look at [V8's implementation](http://code.google.com/p/v8/source/browse/trunk/src/array.js#617) then there [doesn't seem](http://code.google.com/p/v8/source/browse/trunk/src/array.js#321) to be anything magical happening. It uses `.length` to determine the range and then does a `for` loop to copy the right elements (which just requires an object with numerical keys). – pimvdb Feb 27 '12 at 10:21
11

What's happening here is that Sizzle is creating an actual array out of an array-like object. The array-like object doesn't necessarily have the slice() method, so the prototype method has to be called directly. makeArray() returns a copy of that array-like object that is an actual array, and can be used as such else where.

See here for more information about array-like objects.

James Sulak
  • 31,389
  • 11
  • 53
  • 57
6

As BoltClock says, it makes a (shallow) copy of an array. It can also be used to copy something that is almost an array, such as the arguments builtin, which has a length and items but no Array in its prototype chain (and hence no slice method).

harpo
  • 41,820
  • 13
  • 96
  • 131
  • I thought so, but it assigns the result back to the same `array`, so I can't quite figure out what's really happening. – BoltClock Feb 28 '11 at 17:06
  • May I ask why `var` isn't put before it? If a copy is made, then wouldn't it be a new variable, i.e. with `var`? – pimvdb Feb 28 '11 at 17:07
  • @BoltClock, Hmmm... that is odd. Maybe it's to give the Array prototype to something that's not really, like arguments or a jQuery set. – harpo Feb 28 '11 at 17:07
  • @pimvdb, that would depend on the context. It may just be an error :) – harpo Feb 28 '11 at 17:09
  • One possible effect of this would be to get rid of any named members in the Array. (Won't affect the prototype of course.). Like if you had `var array = ['zero','one','two']; array['someProp'] = 'someValue';` You could get rid of `someProp` using the technique in the question. – user113716 Feb 28 '11 at 17:11