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:
- Function Overloading
- The
argumentsobject - 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++:
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: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: 8The 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 calledarguments. Take a look at the following jsFiddle:
(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: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: 8To some, this may seem to make the function invocation a little more verbose; to others, a little more expressive.