简体   繁体   中英

“method overloading” in javascript

So I admit that I'm new to javascript and that I come 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?

看看这篇文章

I 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 combining both examples (using conditions to determine behaviour based on number of arguments and types of arguments).

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.com/search/?p=javascript

This is overloading, not overriding no?

Javascript is weakly typed, so method signatures and native support is out. My recommendation 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'});

A little more comprehensive 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." 

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 complex function that would be performed, and then document it in comments 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 (ie 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;
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM