JSOct 18, 2012 · 4 min read

Digesting JavaScript Good Parts: Arguments

JavaScript can't do function overloading the way C++ can, so handling variable arguments means picking between the arguments object, optional parameters, or passing an object literal. Each has real trade-offs.

A variadic function is one that takes in a variable number of arguments. In this article, I'm going to take a look at some of the different ways this can be handled in JavaScript:

  1. Function Overloading
  2. The arguments object
  3. Passing arguments as an object

Function Overloading

This is an old pattern that I still remember from my C++ days: programmers would define a function multiple times with the same name, but different signatures. When you invoke an overloaded function, the compiler considers the number of arguments, as well as the type of each argument, to determine the correct function to invoke. Needless to say, this gets complicated as the number of arguments increases, and whether or not an argument is required changes.

JavaScript has issues of its own: since it is weakly typed, it cannot distinguish between the two function calls that you might make in C++:

C
void foo(int a, char b){}
void foo(char a, int b){}

Since you can't define two functions with the same name, the internals of foo(a, b) would have to determine which argument is which type.

In JavaScript, instead of function overloading, you can "overload" the signature. Invoking a function without passing in all the parameters in the signature will not cause an error (both a good thing and a bad thing).

Case Study

Consider the following jsFiddle:
JavaScript
function foo( title, x, y ){
  var sum = x + y;
  document.write(title + ": ");
  document.write(sum);
}

foo("bar",3,5);   // bar: 8
foo(3,5);         // 3: NaN
foo(null, 3,5);   // null: 8

The order of the arguments is important; there's no type-checking, and omitting arguments will cause all subsequent arguments to be offset. In cases like this, you'd have to pass null as the first argument, then check to see if typeof title === "string" && title != "".

To avoid passing in null as an argument, we can look at a pattern later where we pass in object literals as arguments.

The arguments Object

When a function is called, an object is made available in the local scope called arguments. Take a look at the following jsFiddle:
JavaScript
(function (){
  for(var i = 0; i < arguments.length; i++){
    document.write("[" + arguments[i] + "]");
  }
})(1,2,3,4);

There is an arguments.length property, and arguments are referenced like arrays with square bracket notation, but arguments is not an array.

Iterating over Arguments

There are two possible ways to iterate over the arguments: for(var i = 0; i < arguments.length; i++) or for(var i in arguments). I found that when using the latter, modifying arguments (such as adding an additional property) will impact the number of iterations, but similar modifications have no impact on arguments.length.

Passing Arguments as an Object

Going back to our example earlier, we can rewrite it so that instead of taking in a comma-delimited list of arguments, we accept a single argument in the form of an object, as seen in this jsFiddle:
JavaScript
function foo( argObject ){
  var x = argObject.x,
      y = argObject.y,
      title = argObject.title,
      sum = argObject.x + argObject.y;

document.write(argObject.title + ": ");
  document.write(sum);
}

document.write("Test 1");
foo({
  title:"bar",
  x: 3,
  y: 5
});   // bar: 8

document.write("Test 2");
foo({
  x: 3,
  y: 5
});   // undefined: 8

document.write("Test 3");
foo({
  title: null,
  x: 3,
  y: 5
});   // null: 8​​

To some, this may seem to make the function invocation a little more verbose; to others, a little more expressive.