Default Arguments in JavaScript Functions
I often run into people who need (for reasons that are beyond me) to be able to give arguments in a javascript function default values. Kinda like what you have in C/C++:
void foo(int a, int b = 42) { ... }
I felt an urge to do it, so I sat down for a few minutes, trying to conjure something nifty that would be intuitive enough for even me to use.
The solution I came up with, and that hopefully will put an end to the I-need-default-arguments-in-javascript rant for good.
The solution is quite simple, and very intuitive. It may have some shortcomings but keep in mind I didn’t explicitly write it for you. You could probably modify my solution to fit your needs anyway.
I’ve seen alot of developers (including myself, long time ago) using this pattern as a workaround for the lack of built-in support for default-arguments.
function foo(a, b)
{
a = typeof(a) != 'undefined' ? a : 42;
b = typeof(b) != 'undefined' ? b : 'default_b';
...
}
Which most developers probably find sufficient, I don’t.
The solution may look scary at a quick first glance, but bear with me. I’ll start by writing the framework-code. The code that will be required for this thing to work.
Function.prototype.defaults = function()
{
var _f = this;
var _a = Array(_f.length-arguments.length).concat(
Array.prototype.slice.apply(arguments));
return function()
{
return _f.apply(_f, Array.prototype.slice.apply(arguments).concat(
_a.slice(arguments.length, _a.length)));
}
}
See that wasn’t so scary :).
In order for this to work you have to declare you functions in a special way. There are basicly two ways of declaring a function.
function foo(a, b)
{
...
}
Is identical to (apart from the lexical difference, and some other minor things)
var foo = function(a, b)
{
...
}
In order for this solution to work you have to declare all functions on which you wish to have default-arguments the latter way.
Usage
var foo = function(a, b)
{
...
}.defaults(42, 'default_b');
Is identical to the first code-block but without adding any code in the function-body.
Example
var bar = function(a, b)
{
}.defaults('default_b');
bar();
// a = undefined, b = 'default_b'
bar(1);
// a = 1, b = 'default_b'
bar(1, 'some_value');
// a = 1, b = 'some_value'
on June 16th, 2006 at 3:55 pm
Okay, I’ll bite… for what reason do “others” claim they need the defaults, defined as part of the parameters?
I can see, if they are “used” to this, that they would like to continue doing something like this, but the…
if( typeof(a) == ‘undefined’ ){
a = 37;
}
or what you originally showed works just fine for me.
Steve
on June 30th, 2006 at 1:38 pm
It’s a pretty handy function, there will be few times when I’ll use it, but I’ll save it for those times. I would like to have seen a little comments in the code, I got it after looking through it a few times, but most people probably won’t bother trying to understand it. Using something you don’t understand is really really bad.
Steve: Yes it works fine to do typeof, but I see no reason to not use fatbrain’s function now that it’s available. Also, there is no way for to detect whether undefined was passed as the value of the argument or if it was omitted when using typeof, while it won’t be a defined property of the arguments object if the argument wasn’t passed.
on July 3rd, 2006 at 2:36 pm
Raeval, I got to correct you: When you submit “undefined” as value for the parameter, typeof will most likely return “string” as datatype.
on July 5th, 2006 at 7:49 am
haha that is way cool! i just found this other site that had:
function(arg1,arg2)
{
var def_arg1 = arg1 || ‘DEFAULT VALUE’;
}
although i can’t dispute the coolness of your function, i also think that all that extra process to save no code space seems redundant
on July 21st, 2006 at 1:49 pm
white: If you mean that passing the string “undefined” will result in typeof(arg)===”string”, that was obvious and not what I was talking about.
If you meant passing undefined, you’re incorrect; (function (x) { return typeof(x); })(undefined) // => “undefined”
on July 25th, 2006 at 5:25 am
Quietly nested in that method is a nice bit of sugar.
Array.apply(null, arguments)
Lovely approach for passing argument objects to .apply without manually iterating over the object.
Immediately useful, thanks a million.
on March 22nd, 2007 at 6:45 am
Wow–only six comments and I have three things to respond to. First of all, thanks so much, fatbrain, for publishing this. It would be useful if it weren’t ClearSilver that I actually needed to have default arguments for.
Iain, the scrap of code you present runs into the danger Raevel is (correctly) talking about: if you pass that function zero or false or anything else JS evaluates as false, it sticks in the default value, even if what you really wanted to pass was zero, false, etc. Bad news. Default arguments are hugely helpful when you decide to add an argument to a function to expand its functionality for a special case but don’t want to have to pick back through your code to fix its previous performance for all the other times you’ve called it. For simple JS it’s totally gratuitous, but for more complex stuff it’s a great time-saver and error-catcher. Finally, I have to say that I cheerfully use code that I don’t understand frequently. While the controlling part of my nature is apt to agree that it’s bad, I think that part is ultimately wrong: if this is something successful and tested, I don’t have to understand anything about it but how to use it.
on April 25th, 2007 at 11:34 am
Thank You
on May 5th, 2007 at 2:48 am
Hi.. I loved your idea, I was trying to create something like this for a while but couldn’t figure out how.. basing it on your code, I created a similar function that causes less troubles (no errors if the function.length
on May 7th, 2007 at 8:37 pm
I added a “minor than” symbol in the previous post and the post is not showing properly, I’ll repost it without the symbol.
fatbrain, I loved your code, I was trying to code something like this but I couldn’t, so I searched and found yours, I modified it a bit so that it won’t throw an error if the defaults array is larger than the arguments one. Also will update parameters that are submitted as null or undefined.
All this changes are not much relevant.. the only problem I found is that you were passing _f as scope of the Function.apply.. instead I think it should be receiving “this” to behave as expected. here’s my version.
Function.prototype.defaults = function(){
var f = this;
var def = Array.prototype.slice.apply(arguments);
function update(a){
var na = Array.prototype.slice.apply(a);
for(var i=0;i
on June 29th, 2007 at 1:19 pm
In Javascript, I use 3 different methods to get this effect…
Optional Function Arguments in JavaScript
Your method is the fourth - Thanks!
on June 29th, 2007 at 6:56 pm
I’ve read hundreds of articles containing js snippets for accomplishing various things, most of which are either no-brainers or completely irrational.
This one is not. Well done.
on July 2nd, 2007 at 12:07 pm
Nice idea and elegant implementation, although I think I am not going to use it because:
1. it is less readable than the “if typeof” version or the shorter “= .. || ..”, because the defaults are seperated (lines of code wise) far from the argument list.
2. if you add another argument to the function you have to update the default list, which might lead to hard to find processing errors. Maybe one could work around by requiring that the default call always get’s the same number of arguments as the function itself expects, causing an error if it doesn’t.
on July 6th, 2007 at 11:16 am
Thanks for all your lovely comments, very much appreciated :-)
on July 13th, 2007 at 8:04 am
I have a hybrid idea that uses your method with associative arrays:
http://www.adventsun.com/code/JS_Function_Defaults.htm
Thanks for pointing me in the right direction! :)
on September 17th, 2007 at 4:07 pm
Your way won’t work with objects.
This way will: http://phpfi.com/263389
Regards
e-voc
on September 17th, 2007 at 4:30 pm
sorry, the last on was buggy.
here’s the working one:
Function.prototype.defaults = function(o) {
var _f = this;
var args = Array.prototype.slice.call(arguments, 1);
return function() {
var a = Array.prototype.slice.call(arguments);
return _f.apply(o, a.concat(args.slice(a.length)));
}
}
function Foo() { this.bla = 1; }
Foo.prototype.foo = function(a, b) {
return this.bla + ‘:’ + a + ‘/’ + b;
};
var f = new Foo;
f.foo = f.foo.defaults(f, 42, ‘default_b’);
f.foo(10, 20); // returns “1:10/20″
f.foo(10); // returns “1:10/default_b”
f.foo(); // returns “1:42/default_b”
on September 17th, 2007 at 4:34 pm
For normal functions, one would pass null or window as execution context
var bar = function (who) { return who; }.defaults(null, ‘me’);
bar();
Regards
e-voc
on October 25th, 2007 at 5:58 pm
Thanks for input e-voc. What if we consider:
Function.prototype.defaults = function()
{
var _f = this;
var _a = Array(_f.length-arguments.length).concat(
Array.prototype.slice.apply(arguments));
return function()
{
return _f.apply(this, Array.prototype.slice.apply(arguments).concat(
_a.slice(arguments.length, _a.length)));
}
}
Or did I get it wrong? Anyhow, give it a testspin and get back to me.
Damn I’m hungry, need food for brain. (I only change the “this” argument in the apply on the inner function)
Cheers // fatbrain
on August 6th, 2008 at 9:39 am
There is an easier way:
function my_func(arg1)
{
if(!arg1){
var arg1=’default_argument_value’;
}
}
on October 6th, 2008 at 9:27 pm
“…if you pass that function zero or false or anything else JS evaluates as false, it sticks in the default value, even if what you really wanted to pass was zero, false, etc. Bad news…”
What about using the “is not exactly equal to” operator, that way you can still pass it false or 0 or something.
a = typeof(a) !== ‘undefined’ ? a : 42;
on November 3rd, 2008 at 12:05 pm
LOL, instead of keeping it simple:
a = typeof(a) != ‘undefined’ ? a : 42;
b = typeof(b) != ‘undefined’ ? b : ‘default_b’;
You decided that create a new function and having to use a new way to declare function, a better idea?
So if I have 1 value I want to default to something, instead of adding one line of code, I have to add 10?
HAHAHA
on December 2nd, 2008 at 8:23 pm
/raises a glass
thanks fatbrain
on March 18th, 2009 at 1:44 pm
hi there..
I am developing a .bat file that required javascript file to run. this javascript uses parameter passed to it by .bat file which invokes it.could anyone tell me how to access this parameter in javascript function ??
thanks in advance
on May 17th, 2009 at 10:21 pm
Default argument values allow to modify functions when modifying mountains of code is silly.
Also default behavior in many cases means only rarely does an extra argument get added.
Why is it so mysterious?
on June 26th, 2009 at 7:29 pm
Maybe I’m crazy, and I only read 75% of the comments, but how do you supply a default value for say… ONLY the fifth parameter of a function?
This is the only way I see how:
var asdf = function(a, b, c, d, e).defaults(undefined,undefined,undefined,undefined,’mydefaultvalue’);
And given how often the later parameters are optional and first ones are required, I’d much rather use your original, inituitive typeof solution which requires no extra code to hunt down or include.
on September 18th, 2009 at 3:31 pm
Although your solution is no doubt “cool”, I can’t see your rational at all. You said the original solution is not sufficient but you gave no reason why, and I don’t see any advantage of your proposed solution over it. You basically replaced a simple one line IF statement that is commonly understood practice throughout the industry (aka a common idiom) with a monster. You would definitely need more justification to do something like this in a production system where there is more than one developer working on it.
on October 1st, 2009 at 12:29 pm
Hello, to the last message of Rohan, there can be several ways to accomplish this, ofcourse you can put any number of if and switch statements but I liked the solution author has gave, its neat and clean. Guess what I am accepting 6 variables and that would have get me to put 6 if else statements. Good work fatbrain!