Arguments.length In Javascript Depends On Invocation Arguments, Not Function Signatures
In Javascript, within a function, you can use "arguments.length" to determine how many arguments were passed-in during the given function invocation. In the past, I've used this to overload Javascript functions. Until I read Eloquent Javascript by Marijn Haverbeke, however, I don't think I had a complete understanding of how the arguments collection worked. In order to drill this information into my head, I wanted to quickly demonstrate that arguments.length relies on the invocation arguments, not the defined parameters (function signature).
Below, I am defining a function signature that contains three parameters. Then, I invoke that function with both less-than and more-than the defined number of parameters.
<!DOCTYPE html>
<html>
<head>
<title>Javascript Arguments Depend On Invocation</title>
<script type="text/javascript">
// I am a function that has THREE defined parameters.
function test( foo, bar, baz ){
// Log the length of the arguments collection.
console.log( arguments.length );
// Log the arguments collection itself.
console.log( arguments );
}
// -------------------------------------------------- //
// -------------------------------------------------- //
// With less than the number of defined arguments.
console.log( "With Two Arguments" );
test( "hey", "cutie" );
// -------------------------------------------------- //
// -------------------------------------------------- //
// With more than the number of defined arguments.
console.log( "With Four Arguments" );
test( "hey", "there", "cutie", "pie" );
</script>
</head>
<body>
<!-- Left intentionally blank. -->
</body>
</html>
When we run this code, we get the following console output:
With Two Arguments
2
["hey", "cutie"]With Four Arguments
4
["hey", "there", "cutie", "pie"]
As you can see, the arguments collection (including the arguments.length property) depends only on the arguments used during invocation - not on the parameters defined as part of the method signature. Ironically, I've leveraged this fact before; but, like I said, I don't think I was consciously aware of the underlying mechanics.
Want to use code from this post? Check out the license.
Reader Comments
Good call, Ben! The whole concept of a method signature doesn't seem very JavaScript, does it? In Java, the signature is critical to method binding. And even Ruby, which lets you get away with anything, complains if you don't uphold the contract in the method signature.
If you do want to know the number of arguments that are defined for a function, so that for example you can compare what you were expecting to what you actually get, you can use something similar to the following:
function fnGreat(arg1, arg2, arg3){
console.log(fnGreat.length == arguments.length);
}
fnGreat(1, 2);
When the function isn't named, such as the following:
var fnGreat = function(agr1, agr2, arg3){
console.log(arguments.callee.length == arguments.length);
}
fnGreat(1, 2);
As "callee" is a reference to the function that was called, you can access that function's length property. According to https://developer.mozilla.org/en/JavaScript/Reference/Functions_and_function_scope/arguments/callee it is deprecated, so if you want to be sure to get the length of a function, make sure it is a named function.
@David,
And, ColdFusion is kind of in between - you can define a whole bunch of arguments, but mark some of them as optional and even give them default values. It's interesting to see how each language handles this task.
@Danilo,
Yeah, deprecating the "arguments.callee" makes recursion a bit more complex. You can no longer use anonymous functions. Named functions, as you point out, do the trick; but, sometimes, it's superfluous.
Have you read this interesting approach to function overloading? http://ejohn.org/blog/javascript-method-overloading/
callee is removed in strict mode as it breaks encapsulation. I thought the same was true of function.length at least in becoming a deprecated or removed method.
@Drew,
Thanks for the link - John always has such elegant solutions. According to the Mozilla Dev Center, I think "function.arity" is being deprecated; not sure about function.length". I've never actually used either in my code yet.... YET! :)
@Ben, yep arity is apparently the CS notion of the arguments of a function. At least that's what I read from some arcane manuscript long before the days of duck punching :D!
@Drew,
According to Wikipedia, it also applied to operators as well.