Is it possible to send a variable number of arguments to a JavaScript function?
Asked Answered
I

12

202

Is it possible to send a variable number of arguments to a JavaScript function, from an array?

var arr = ['a','b','c']

var func = function()
{
    // debug 
    alert(arguments.length);
    //
    for(arg in arguments)
        alert(arg);
}

func('a','b','c','d'); // prints 4 which is what I want, then 'a','b','c','d'
func(arr); // prints 1, then 'Array'

I've recently written a lot of Python and it's a wonderful pattern to be able to accept varargs and send them. e.g.

def func(*args):
   print len(args)
   for i in args:
       print i

func('a','b','c','d'); // prints 4 which is what I want, then 'a','b','c','d'
func(*arr) // prints 4 which is what I want, then 'a','b','c','d'

Is it possible in JavaScript to send an array to be treated as the arguments array?

Indecorum answered 24/12, 2009 at 17:2 Comment(4)
Note that its not a good idea to use a for - in loop with the arguments object - a 'normal' for loop iterating over the length property should be used insteadAbbottson
it's never been a problem, can you ellaborate as to why that is the case? arguments object is almost always small enough to have a negligible performance improvement for using the agruments[0..length-1] version.Indecorum
Possible duplicate of JavaScript variable number of arguments to functionVibrato
I think that arguments is not an actual array, but a special object, so the "in" syntax might not work, depending on the JS implementation.Choose
M
264

Update: Since ES6, you can simply use the spread syntax when calling the function:

func(...arr);

Since ES6 also if you expect to treat your arguments as an array, you can also use the spread syntax in the parameter list, for example:

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

const values = ['a', 'b', 'c']
func(...values)
func(1, 2, 3)

And you can combine it with normal parameters, for example if you want to receive the first two arguments separately and the rest as an array:

function func(first, second, ...theRest) {
  //...
}

And maybe is useful to you, that you can know how many arguments a function expects:

var test = function (one, two, three) {}; 
test.length == 3;

But anyway you can pass an arbitrary number of arguments...

The spread syntax is shorter and "sweeter" than apply and if you don't need to set the this value in the function call, this is the way to go.

Here is an apply example, which was the former way to do it:

var arr = ['a','b','c'];

function func() {
  console.log(this); // 'test'
  console.log(arguments.length); // 3

  for(var i = 0; i < arguments.length; i++) {
    console.log(arguments[i]);
  }

};

func.apply('test', arr);

Nowadays I only recommend using apply only if you need to pass an arbitrary number of arguments from an array and set the this value. apply takes is the this value as the first arguments, which will be used on the function invocation, if we use null in non-strict code, the this keyword will refer to the Global object (window) inside func, in strict mode, when explicitly using 'use strict' or in ES modules, null will be used.

Also note that the arguments object is not really an Array, you can convert it by:

var argsArray = Array.prototype.slice.call(arguments);

And in ES6:

const argsArray = [...arguments] // or Array.from(arguments)

But you rarely use the arguments object directly nowadays thanks to the spread syntax.

Maneater answered 24/12, 2009 at 17:8 Comment(5)
Thanks, apply does the trick, call in this case does not work. was that written in by mistake?Indecorum
How do you do it if the function is actually a member of a class? Is this right? theObject.member.apply(theObject, arguments);Damage
Array.prototype.slice.call(arguments); prevents browser JS optimizations like V8. Details hereCurlpaper
1. Apparently, arguments is planned to be deprecated in favor of the spread operator. I don't have a source for this, but I heard it somewhere. 2. MDN states that using slice on the arguments object prevents optimizations in engines like V8. They suggest using the "despised Array constructor", Array.from(arguments), or [...arguments]. Would you care to update your answer for ES2015?Shulamite
NB: I went ahead and wrote my own answer.Shulamite
A
78

You can actually pass as many values as you want to any javascript function. The explicitly named parameters will get the first few values, but ALL parameters will be stored in the arguments array.

To pass the arguments array in "unpacked" form, you can use apply, like so (c.f. Functional Javascript):

var otherFunc = function() {
   alert(arguments.length); // Outputs: 10
}

var myFunc = function() {
  alert(arguments.length); // Outputs: 10
  otherFunc.apply(this, arguments);
}
myFunc(1,2,3,4,5,6,7,8,9,10);
Arjun answered 24/12, 2009 at 17:8 Comment(0)
B
23

The splat and spread operators are part of ES6, the planned next version of Javascript. So far only Firefox supports them. This code works in FF16+:

var arr = ['quick', 'brown', 'lazy'];

var sprintf = function(str, ...args)
{
    for (arg of args) {
        str = str.replace(/%s/, arg);
    }
    return str;
}

sprintf.apply(null, ['The %s %s fox jumps over the %s dog.', ...arr]);
sprintf('The %s %s fox jumps over the %s dog.', 'slow', 'red', 'sleeping');

Note the awkard syntax for spread. The usual syntax of sprintf('The %s %s fox jumps over the %s dog.', ...arr); is not yet supported. You can find an ES6 compatibility table here.

Note also the use of for...of, another ES6 addition. Using for...in for arrays is a bad idea.

Bridget answered 7/9, 2013 at 11:16 Comment(1)
Normal syntax for spread is now supported in Firefox and ChromeBrainy
S
9

There are two methods as of ES2015.

The arguments Object

This object is built into functions, and it refers to, appropriately, the arguments of a function. It is not technically an array, though, so typical array operations won't work on it. The suggested method is to use Array.from or the spread operator to create an array from it.

I've seen other answers mention using slice. Don't do that. It prevents optimizations (source: MDN).

Array.from(arguments)
[...arguments]

However, I would argue that arguments is problematic because it hides what a function accepts as input. An arguments function typically is written like this:

function mean(){
    let args = [...arguments];
    return args.reduce((a,b)=>a+b) / args.length;
}

Sometimes, the function header is written like the following to document the arguments in a C-like fashion:

function mean(/* ... */){ ... }

But that is rare.

As for why it is problematic, take C, for example. C is backwards compatible with an ancient pre-ANSI dialect of the language known as K&R C. K&R C allows function prototypes to have an empty arguments list.

int myFunction();
/* This function accepts unspecified parameters */

ANSI C provides a facility for varargs (...), and void to specify an empty arguments-list.

int myFunction(void);
/* This function accepts no parameters */

Many people inadvertently declare functions with an unspecified arguments list (int myfunction();), when they expect the function to take zero arguments. This is technically a bug because the function will accept arguments. Any number of them.

A proper varargs function in C takes the form:

int myFunction(int nargs, ...);

And JavaScript actually does have something similar to this.

Spread Operator / Rest Parameters

I've already shown you the spread operator, actually.

...name

It's pretty versatile, and can also be used in a function's argument-list ("rest parameters") to specify varargs in a nicely documented fashion:

function mean(...args){
    return args.reduce((a,b)=>a+b) / args.length;
}

Or as a lambda expression:

((...args)=>args.reduce((a,b)=>a+b) / args.length)(1,2,3,4,5); // 3

I much prefer the spread operator. It is clean and self-documenting.

Shulamite answered 27/5, 2017 at 16:30 Comment(1)
thank you for the updated answer, this post predates ES 2015 so i'm glad you filled in more recent optionsIndecorum
G
8

The apply function takes two arguments; the object this will be binded to, and the arguments, represented with an array.

some_func = function (a, b) { return b }
some_func.apply(obj, ["arguments", "are", "here"])
// "are"
Geronimo answered 24/12, 2009 at 17:11 Comment(0)
A
5

It's called the splat operator. You can do it in JavaScript using apply:

var arr = ['a','b','c','d'];
var func = function() {
    // debug 
    console.log(arguments.length);
    console.log(arguments);
}
func('a','b','c','d'); // prints 4 which is what I want, then 'a','b','c','d'
func(arr); // prints 1, then 'Array'
func.apply(null, arr); 
Airdrop answered 24/12, 2009 at 17:17 Comment(0)
C
4

With ES6 you can use rest parameters for varagrs. This takes the argument list and converts it to an array.

function logArgs(...args) {
    console.log(args.length)
    for(let arg of args) {
        console.log(arg)
    }
}
Chrysanthemum answered 21/8, 2018 at 23:10 Comment(0)
S
2
(function(window) {
  var proxied = window.alert;
  window.alert = function() {
    return proxied.apply(window, arguments);
  };
}(this));

alert(13, 37);
Surfboarding answered 25/10, 2013 at 10:1 Comment(0)
O
2

This is a sample program for calculating sum of integers for variable arguments and array on integers. Hope this helps.

var CalculateSum = function(){
    calculateSumService.apply( null, arguments );
}

var calculateSumService = function(){
    var sum = 0;

    if( arguments.length === 1){
        var args = arguments[0];

        for(var i = 0;i<args.length; i++){
           sum += args[i]; 
        }
    }else{
        for(var i = 0;i<arguments.length; i++){
           sum += arguments[i]; 
        }        
    }

     alert(sum);

}


//Sample method call

// CalculateSum(10,20,30);         

// CalculateSum([10,20,30,40,50]);

// CalculateSum(10,20);
Olwena answered 8/2, 2015 at 16:48 Comment(3)
Some notes: 1. var declares a function scope variable. The new let and const keywords (ES 2015) declare block scope variables. Before ES 2015, though, the variables should have still been hoisted to the top of the function as a matter of practice. 2. your function breaks when given 1 integer value because of your erroneous acceptance of an array as an argument (the question asks about varargs; not accepting arrays as arguments): CalculateSum(6) -> 0. (continued in next post)Shulamite
3. Don't use debug functions like alert. Actually, just don't use alert/prompt/confirm, period. Use console.log instead when debugging. 4. The function should be returning a value, not alerting it. 5. avoid PascalCase unless it refers to a "type" of data. I.e. a class. Use camelCase or under_score instead. 4. I don't like the way you declare your functions. var f = function(){ ... } implies that you want it to change at some point, which is probably not your intent. Use the conventional function name(){ ... } syntax instead.Shulamite
To demonstrate all of these critique points, here is an improved version of the function in your answer.Shulamite
N
1

For those who were redirected here from Passing variable number of arguments from one function to another (which should not be marked as a duplicate of this question):

If you're trying to pass a variable number of arguments from one function to another, since JavaScript 1.8.5 you can simply call apply() on the second function and pass in the arguments parameter:

var caller = function()
{
    callee.apply( null, arguments );
}

var callee = function()
{
    alert( arguments.length );
}

caller( "Hello", "World!", 88 ); // Shows "3".

Note: The first argument is the this parameter to use. Passing null will call the function from the global context, i.e. as a global function instead of the method of some object.

According to this document, the ECMAScript 5 specification redefined the apply() method to take any "generic array-like object", instead of strictly an Array. Thus, you can directly pass the arguments list into the second function.

Tested in Chrome 28.0, Safari 6.0.5, and IE 10. Try it out with this JSFiddle.

Nadabas answered 31/7, 2013 at 14:29 Comment(0)
A
0

Yes you can pass variable no. of arguments to a function. You can use apply to achieve this.

E.g.:

var arr = ["Hi","How","are","you"];

function applyTest(){
    var arg = arguments.length;
    console.log(arg);
}

applyTest.apply(null,arr);
Adame answered 29/5, 2017 at 4:18 Comment(0)
C
0

Do you want your function to react to an array argument or variable arguments? If the latter, try:

var func = function(...rest) {
  alert(rest.length);

  // In JS, don't use for..in with arrays
  // use for..of that consumes array's pre-defined iterator
  // or a more functional approach
  rest.forEach((v) => console.log(v));
};

But if you wish to handle an array argument

var fn = function(arr) {
  alert(arr.length);

  for(var i of arr) {
    console.log(i);
  }
};
Ceciliacecilio answered 5/1, 2019 at 1:26 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.