Categories:

Converting objects to arrays using Array.prototype.slice.call()

Last updated: Sept 25th, 2014

A line you may have encountered every now and then inside some JavaScript functions looks like this:

Array.prototype.slice.call(arguments, 1)

And just when you think you've finally gotten a handle on the language, cryptic lines like the above shake your confidence, as JavaScript often will do. In this short tutorial, lets elaborate on the subject line and delve into just what Array.prototype.slice.call() is, works, and how its useful.

Arrays versus array-like objects

In JavaScript, there are arrays, then there are array-like objects. The later is any object with a "length" property that returns the number of elements inside the object, plus numeric indices giving access to elements inside it. Examples of this include the arguments array of a function, HTMLCollection collections, and custom objects with a length property and numeric indices. The following are all array-like objects in JavaScript:

function myfunc(){
	var args = arguments // array-like collection
	for (var i=0; i<arguments.length; i++){
		//do something with each argument/parameter passed into function
	}
}
var uls = document.getElementsByTagName("ul") // array-like collection
var myobject ={ // array-like collection
	length: 4,
	'0': 'zero',
	'1': 'one',
	'2': 'two',
	'3': 'three'
}

While such objects may appear to be arrays in that individual elements within it can be accessed numerically, for example

arguments[0] // access first argument within arguments array
uls[2] // access 3rd UL on the page
myobject.length // returns 4

A quick test for "arrayness" on any of them shatters that illusion:

if (Array.isArray(uls)){ // Returns false. isArray() is supported in IE9+, Firefox1.5+ Chrome, Safari and Opera 10.5+
	//do something
}

The difference between an array and an object masquerading as one lies in the extensive list of useful methods the former has at its disposal, which at times surely can come in handy when working with the later as well. And that's where the cryptic Array.prototype.slice.call comes in.

Using Array.prototype.slice.call to convert Array-like objects into real arrays

Array.prototype.slice.call() serves as a quick way to turn any array-like object into a true array. Most of us are already familiar with Array's slice(start, [end]) method to return a "slice" of an array:

["zero", "one", "two", "three"].slice(1) // returns "one", "two", "three"
["zero", "one", "two", "three"].slice(0, 2) // returns "zero", "one"

The slice() method in this case belongs to the Array object (its "this" object points to our array instance). By calling the slice() method as a method of the desired array-like object instead, that process coerces the later into a true array at the same time. And thankfully JavaScript makes it easy to do just that, invoke a method as if it belongs to a different host function, via the call() and apply() methods. When we invoke a method this way, the resulting "this" object points not to the original function associated with it, but the new function.

Armed with this knowledge, we are half way to understanding why the following works in converting an array-like object into a true array:

var myobject ={ // array-like collection
	length: 4,
	'0': 'zero',
	'1': 'one',
	'2': 'two',
	'3': 'three'
}

var myarray = Array.prototype.slice.call(myobject) // returns myobject as a true array: ["zero", "one", "two", "three"]

And since the slice() method supports optional "start" and "end" parameters to return just a portion of an array as a new array, we can do the following:

var myarray = Array.prototype.slice.call(myobject, 1) 
	// returns ["one", "two", "three"]
var myarray = Array.prototype.slice.call(myobject, 0, 
	2) // returns ["zero", "one"]

The one remaining question is why we're calling slice() on the prototype object of Array instead of an array instance. The reason is because this is the most direct route to accessing the slice() method of Array when that's all we're interested in; we could have first created an array instance, but that's less efficient and arguably more abstruse:

 var myarray = new Array().prototype.slice.call(myobject) // less efficient

Now that we've demystified Array.prototype.slice.call(), lets peer into the not so distant future where a more official way of converting array-like objects into arrays exists, and that is Array.from().

Converting array-like objects into arrays using Array.from() method (ECMAScript 6)