So I admit that I'm new to javascript and that I e from a C.+ background ("Hi, I'm Bob, I'm a class-based static language user", chorus "hi Bob!").
I find that I often end up writing functions like:
function someFunc()
{
if (arguments.length === 0 ){
...
} else {
...
}
}
(where there might be three such cases). Or, alternatively, I write the difference into the name:
function someFuncDefault() { ... };
function someFuncRealArg(theArg) { ... };
(Substitute "RealArg" for some semantically contentful phrase).
Is there a better pattern for this kind of thing?
So I admit that I'm new to javascript and that I e from a C.+ background ("Hi, I'm Bob, I'm a class-based static language user", chorus "hi Bob!").
I find that I often end up writing functions like:
function someFunc()
{
if (arguments.length === 0 ){
...
} else {
...
}
}
(where there might be three such cases). Or, alternatively, I write the difference into the name:
function someFuncDefault() { ... };
function someFuncRealArg(theArg) { ... };
(Substitute "RealArg" for some semantically contentful phrase).
Is there a better pattern for this kind of thing?
Share Improve this question edited Feb 18, 2009 at 18:24 Afton asked Feb 17, 2009 at 22:24 AftonAfton 1841 silver badge10 bronze badges 2- Isn't this an example of method overLOADing? – Tim Frey Commented Feb 17, 2009 at 22:35
- 1 I highly remend Douglas Crockford's videos for learning javascript... they've helped me actually understand how it all fits together: video.yahoo./search/?p=javascript – Akrikos Commented Feb 17, 2009 at 22:54
7 Answers
Reset to default 3I don't know that I would do it this way, but it seems like it might make your code mildly less unmanageable:
function someFunc() {
switch (arguments.length) {
case 0: noArgs();
case 1: oneArg(arguments[0]);
case 2: twoArgs(arguments[0], arguments[1]);
}
function noArgs() {
// ...
}
function oneArg(a) {
// ...
}
function twoArgs(a, b) {
// ...
}
}
Another example might be:
function someFunc(a, b) {
if ('string' == typeof a) {
// ...
} else if ('number' == typeof a) {
// ...
}
}
And of course you can probably create something quite unmanageable by bining both examples (using conditions to determine behaviour based on number of arguments and types of arguments).
This is overloading, not overriding no?
Javascript is weakly typed, so method signatures and native support is out. My remendation is to pass an extensible object as the solitary argument. Inspect and handle the existance of properties on the param object as you wish.
What advantage does this have over arguments? Well it lets you be explicit about your intentions where you call, and unambiguous about the meaning of arg1 and arg2 where you recieve, and it lets you abstract to a custom data object class you can extend functionality to.
function someFunc(params)
{
var x = params.x || defaultX;
var y = params.y || defaultY;
//businesslogic
}
someFunc({x:'foo',y:'bar'});
someFunc({y:'baz'});
In Javascript, all arguments are optional.
You might try something like:
Edit (better method that doesn't break for values whose 'truthiness' is false):
function bar(arg1, arg2) {
if(arg1 === undefined) { set default }
if(arg2 === undefined) { set default }
//do stuff here
}
Old method that breaks for falsey values:
function foo(arg1, arg2) {
if(!arg1) { set default }
if(!arg2) { set default }
//do stuff here
}
A great place to start with javascript are Douglas Crockford's javascript lectures: http://video.yahoo./search/?p=javascript
Javascript lets you get really lazy with this (not quite as lazy as Python, but pretty lazy).
function someFunc(arg1, arg2)
{
if(typeof(arg1) == "undefined") {
arg1 = default;
}
...
}
So you don't really need to overload. Javascript won't yell at you for passing the wrong number of parameters.
Everyone came close, I think that the real issue here is that in JavaScript you shouldn't change behavior based on parameters being passed in.
Since JavaScript makes all parameters optional you could follow the concise method of using this convention:
function foo(bar, baz) {
bar = bar || defaultBar;
baz = baz || defaultBaz;
.
.
.
}
Personally, I prefer to write the most plex function that would be performed, and then document it in ments so that others know that they do not have to send all the arguments.
//concat(str1, str2 [,str3 [,str4 [,str5]]])
function concat(str1, str2, str3, str4, str5) {
var str = str1 + str2;
if(str3 != undefined)
str += str3;
if(str4 != undefined)
str += str4;
if(str5 != undefined)
str += str5;
return str;
}
I have also found situations where the argument order would matter in a normal function, but sometimes I would want to sent the arguments seperately (i.e. I would want to send str3 and str5 but not str4). For this, I use an object and test the known properties
//concat({str1:string, str2:string, str3:string, str4:string, str5:string})
//str3, str4, and str5 are optional
function concat(strngs) {
var str = strngs.str1 + strngs.str2;
if(strngs.str3 != undefined)
str += strngs.str3;
if(strngs.str4 != undefined)
str += strngs.str4;
if(strngs.str5 != undefined)
str += strngs.str5;
return str;
}
A little more prehensive overloading mechanism is offered by bob.js:
var notify = new bob.fn.overloadFunction([
{
condition: function(msg) { return bob.utils.isString(msg); },
overload: function(msg) {
console.log(msg);
}
},
{
condition: function(bSayHello) { return bob.utils.isBoolean(bSayHello); },
overload: function(bSayHello, msg) {
msg = bSayHello ? 'Hello: ' + msg : msg;
console.log(msg);
}
}
]);
Calling the overloaded function:
notify('Simple sentence.');
// Output:
// Simple sentence.
notify(true, 'Greeting sentence.');
// Output:
// Hello: Greeting sentence.
notify(123);
// JavaScript Error:
// "No matching overload found."