JavaScript Function Arguments: They’re An Array And You Can Treat Them As Such

One of the nicest features of JavaScript is the ability to treat function arguments as an array. We all know how to write a function that takes a known number of arguments:

function foo(bar) {
	alert(bar);
}

function getArea(shape, measure, unit) {
	var output = 'The area of a ' + measure + ' ' + unit + ' ' + shape + ' is ';
	switch(shape) {
		case 'square':
			output += (measure * measure);
			break;
		case 'circle':
			output += (3.14 * (measure * measure));
			break;
		default:
			output += 'unknown to this function.';
	}
	alert(output);
}

But sometimes, your script will require you to pass some unknown number of parameters to a function. So how do you deal with that?

Luckily, JavaScript functions treat all of their arguments as an array. So, if you’re not certain how many arguments your function will take, don’t declare them in your function code; simply use the reserved word arguments to iterate the array of arguments passed to the function.

function allTheAnimals() {
	var output = 'The animals you provided are: ';
	for(var i = 0; i < arguments.length; i++) {
		output += arguments[i] + ', ';
	}
	output = output.substring(0, (output.length - 2)); //remove trailing comma and space
	alert(output);
}

Note that we can ask for specific indexes of the array, but should ensure there are at least that many elements in the array before asking:

function threeIsAMagicNumber() {
	if(arguments.length < 3) {
		alert('There is no third argument!');
	}
	else {
		alert('The value of the third argument passed to this function is ' + arguments[2].toString());
	}
}

We can even pass an unknown number of arguments from one function to another, via the apply method:

function parentFunction() {
	var output = 'Arguments received by parent function: ';
	for(var i = 0; i < arguments.length; i++) {
		output += arguments[i] + ', ';
	}
	output = output.substring(0, (output.length - 2));
	output += "\n\nDo you want to send these to the child function? OK to submit to child function, Cancel to abort.";
	if(confirm(output)) {
		childFunction.apply(this, arguments);
	}
}

function childFunction() {
	var output = 'Arguments received by the child function: ';
	for(var i = 0; i < arguments.length; i++) {
		output += arguments[i] + ', ';
	}
	output = output.substring(0, (output.length - 2));
	alert(output);
}

You can see a demonstration of all these here: http://demo.dougv.com/js_function_arguments_array/

I distribute code under the GNU GPL version 3.

Comments

  1. says

    The bonus “arguments” parameter is not an array, but is an object with array-like properties. Because of a design error, the “arguments” property does not have all of the typical array methods available to it. For this and other reasons, I believe it is preferable to use named arguments when passing an unknown number of values into a function. Then, you can have default parameters and use array functions on arrays without having to worry about the order of your parameters. For example:

    var allTheAnimals = function (args) {
      args.output = (typeof args.output === "string") ? args.output : "The animals you provided are: ";
      alert(args.output + args.animals.sort().join(", "));
    };
    
    allTheAnimals({animals: ["Dog", "Cow", "Chicken", "Cat"]});
    
  2. says

    Scriptar: As you note, technically, the arguments of a function are a collection (a collection, for most intents and purposes, is an array of similar objects). For convenience, thanks to weak typing and implicit type casting, we can almost always treat the arguments of a function as an array of strings. As such, using the identity operator, as you note, to test for strings will almost always yield true, unless we are explicitly passing DOM or other objects.

  3. says

    What I was attempting to demonstrate from my example is that, while you could use the “arguments” object’s array-like subscript syntax to access its values (as with all JavaScript objects), and it does have an array-like “length” property; the “arguments” collection is not an array and you can’t treat it as such because array methods such as sort(), join(), slice(), push() and pop() will not work on it. It is better to pass an actual array as one parameter to a function. Better yet, a single object with named properties where the function checks expected property existence and validity by name instead of by index:

    function doStuff_v1() {
      // error, can't use join() method...
      alert("My arguments are: " + arguments.join(", "));
    }
    function doStuff_v2(arr) {
      // pretty good...
      alert("My arguments are: " + arr.join(", "));
    }
    function doStuff_v3(args) {
      // best pattern...
      alert(args.msg + args.arr.join(", "));
    }
    
    try {
      // errors
    	doStuff_v1("arg1", "arg2", "arg3");
    } catch (e) {
    	alert("Error: " + e.message);
    }
    
    // displays "My arguments are: arg1, arg2, arg3"
    doStuff_v2(["arg1", "arg2", "arg3"]);
    
    // displays: "Last time: arg1, arg2, arg3"
    doStuff_v3({msg: "Last time: ", arr: ["arg1", "arg2", "arg3"]});
  4. says

    Scriptar: Good points.

    I probably have oversold the idea of JavaScript arguments being an array. As you note, standard array functions built in to JavaScript will not work on a collection.

    My target audience — newer programmers — tends not to be that sophisticated, so I try as often as possible to employ generalities that usually hold true. Even so, it’s definitely valuable to note that contrary to the title of this post, JavaScript function arguments are not truly an array. Thanks for keeping me honest.

Trackbacks

Leave a Reply

Your email address will not be published. Required fields are marked *