How can I convert the “arguments” object to an array in JavaScript?

How can I convert the “arguments” object to an array in JavaScript?

The arguments object in JavaScript is an odd wart—it acts just like an array in most situations, but it’s not actually an array object. Since it’s really something else entirely, it doesn’t have the useful functions from Array.prototype like forEach, sort, filter, and map.
It’s trivially easy to construct a new array from an arguments object with a simple for loop. For example, this function sorts its arguments:
function sortArgs() {
var args = [];
for (var i = 0; i < arguments.length; i++) args[i] = arguments[i]; return args.sort(); } However, this is a rather pitiful thing to have to do simply to get access to the extremely useful JavaScript array functions. Is there a built-in way to do it using the standard library?

Solutions/Answers:

Solution 1:

ES6 using rest parameters

If you are able to use ES6 you can use:

Rest Parameters

function sortArgs(...args) {
  return args.sort(function (a, b) { return a - b; });
}

document.body.innerHTML = sortArgs(12, 4, 6, 8).toString();

As you can read in the link

The rest parameter syntax allows us to represent an indefinite number of arguments as an array.

If you are curious about the ... syntax, it is called Spread Operator and you can read more here.

ES6 using Array.from()

Using Array.from:

function sortArgs() {
  return Array.from(arguments).sort(function (a, b) { return a - b; });
}

document.body.innerHTML = sortArgs(12, 4, 6, 8).toString();

Array.from simply convert Array-like or Iterable objects into Array instances.



ES5

You can actually just use Array‘s slice function on an arguments object, and it will convert it into a standard JavaScript array. You’ll just have to reference it manually through Array’s prototype:

function sortArgs() {
    var args = Array.prototype.slice.call(arguments);
    return args.sort();
}

Why does this work? Well, here’s an excerpt from the ECMAScript 5 documentation itself:

NOTE: The slice function is intentionally generic; it does not require that its this value be an Array object. Therefore it can be transferred to other kinds of objects for use as a method. Whether the slice function can be applied successfully to a host object is implementation-dependent.

Therefore, slice works on anything that has a length property, which arguments conveniently does.


If Array.prototype.slice is too much of a mouthful for you, you can abbreviate it slightly by using array literals:

var args = [].slice.call(arguments);

However, I tend to feel that the former version is more explicit, so I’d prefer it instead. Abusing the array literal notation feels hacky and looks strange.

Solution 2:

It’s also worth referencing this Bluebird promises library wiki page that shows how to manage the arguments object into array in a way that makes the function optimizable under V8 JavaScript engine:

function doesntLeakArguments() {
    var args = new Array(arguments.length);
    for(var i = 0; i < args.length; ++i) {
        args[i] = arguments[i];
    }
    return args;
}

This method is used in favor of var args = [].slice.call(arguments);. The author also shows how a build step can help reduce the verbosity.

Solution 3:

function sortArgs(){ return [].slice.call(arguments).sort() }

// Returns the arguments object itself
function sortArgs(){ return [].sort.call(arguments) }

Some array methods are intentionally made not to require the target object to be an actual array. They only require the target to have a property named length and indices (which must be zero or larger integers).

[].sort.call({0:1, 1:0, length:2}) // => ({0:0, 1:1, length:2})

Solution 4:

Use:

function sortArguments() {
  return arguments.length === 1 ? [arguments[0]] :
                 Array.apply(null, arguments).sort();
}

Array(arg1, arg2, ...) returns [arg1, arg2, ...]

Array(str1) returns [str1]

Array(num1) returns an array that has num1 elements

You must check number of arguments!

Array.slice version (slower):

function sortArguments() {
  return Array.prototype.slice.call(arguments).sort();
}

Array.push version (slower, faster than slice):

function sortArguments() {
  var args = [];
  Array.prototype.push.apply(args, arguments);
  return args.sort();
}

Move version (slower, but small size is faster):

function sortArguments() {
  var args = [];
  for (var i = 0; i < arguments.length; ++i)
    args[i] = arguments[i];
  return args.sort();
}

Array.concat version (slowest):

function sortArguments() {
  return Array.prototype.concat.apply([], arguments).sort();
}

Solution 5:

If you’re using jQuery, the following is a good deal easier to remember in my opinion:

function sortArgs(){
  return $.makeArray(arguments).sort();
}

Solution 6:

In ECMAScript 6 there’s no need to use ugly hacks like Array.prototype.slice(). You can instead use spread syntax (...).

(function() {
  console.log([...arguments]);
}(1, 2, 3))

It may look strange, but it’s fairly simple. It just extracts arguments‘ elements and put them back into the array. If you still don’t understand, see this examples:

console.log([1, ...[2, 3], 4]);
console.log([...[1, 2, 3]]);
console.log([...[...[...[1]]]]);

Note that it doesn’t work in some older browsers like IE 11, so if you want to support these browsers, you should use Babel.