43

Can I call a function with array of arguments in a convenient way in JavaScript?

Example:

var fn = function() {
    console.log(arguments);
}

var args = [1,2,3];

fn(args);

I need arguments to be [1,2,3], just like my array.

Michał Perłakowski
  • 88,409
  • 26
  • 156
  • 177
David Hellsing
  • 106,495
  • 44
  • 176
  • 212

2 Answers2

62

Since the introduction of ES6, you can sue the spread syntax in the function call:

const args = [1,2,3];

fn(...args);

function fn() {
  console.log(arguments);
}

Before ES6, you needed to use apply.

var args = [1,2,3];
fn.apply(null, args);

function fn() {
  console.log(arguments);
}

Both will produce the equivalent function call:

fn(1,2,3);

Notice that I used null as the first argument of the apply example, which will set the this keyword to the global object (window) inside fn or undefined under strict mode.

Also, you should know that the arguments object is not an array, it's an array-like object, that contains numeric indexes corresponding to the arguments that were used to call your function, a length property that gives you the number of arguments used.

In ES6, if you want to access a variable number of arguments as an array, you can also use the rest syntax in the function parameter list:

function fn(...args) {
  args.forEach(arg => console.log(arg))
}

fn(1,2,3)

Before ES6, if you wanted to make an array from your arguments object, you commonly used the Array.prototype.slice method.

function fn() {
  var args = Array.prototype.slice.call(arguments);
  console.log(args);
}

fn(1,2,3);

Edit: In response to your comment, yes, you could use the shift method and set its returned value as the context (the this keyword) on your function:

fn.apply(args.shift(), args);

But remember that shift will remove the first element from the original array, and your function will be called without that first argument.

If you still need to call your function with all your other arguments, you can:

fn.apply(args[0], args);

And if you don't want to change the context, you could extract the first argument inside your function:

function fn(firstArg, ...args) {
   console.log(args, firstArg);
}

fn(1, 2, 3, 4)

In ES5, that would be a little more verbose.

function fn() {
  var args = Array.prototype.slice.call(arguments),
        firstArg = args.shift();

  console.log(args, firstArg);
}

fn(1, 2, 3, 4);
Christian C. Salvadó
  • 807,428
  • 183
  • 922
  • 838
  • What if I want the scope to be the first element of the Array? do I need to fake it using shift() ? – David Hellsing Dec 10 '09 at 16:04
  • @David: What do you mean by scope? The `this` keyword ? – Christian C. Salvadó Dec 10 '09 at 16:10
  • Yes, using apply(), the first argument becomes the scope(this) for the function, right? The scope in this case need to be the first array element. – David Hellsing Dec 10 '09 at 16:14
  • "fn.apply(args.shift(), args);" -- Does javascript guarantee a left-to-right function argument evaluation order? Is args passed by reference? Expressions of form "f(modify(object), object))" trigger my spider senses... – Jonas Kölker Dec 10 '09 at 16:25
  • 1
    @CMS This question is only about calling a function with array of arguments. I think that talking about `arguments` not being a real array is little off-topic here (it would help OP, but not future visitors). Adding a link to [How can I convert the “arguments” object to an array in JavaScript?](http://stackoverflow.com/questions/960866/how-can-i-convert-the-arguments-object-to-an-array-in-javascript) would be enough. – Michał Perłakowski Jan 24 '16 at 17:09
13

In ECMAScript 6, you can use spread syntax (...) for that purpose. It's way simpler and easier to understand than Function.prototype.apply().

Code example:

const fn = function() {
  console.log(arguments);
}

const args = [1,2,3];

fn(...args);
Michał Perłakowski
  • 88,409
  • 26
  • 156
  • 177