JavaScript only pretends to support function overloading

I frequently use method overloading a lot in my C# code to allow optional parameters, so when I wanted to implement a simple popup function with optional support for virtual root and website based on the url, here's what I came up with:

function showPopUp(virtual, url, height, width)
{
 
if(location.pathname.indexOf(virtual)>=0)
 { 
  
//we're running in the virtual root, so prepend it to the url
  
url=virtual+url;
 }
 showPopUp(url, height, width);
}

function showPopUp(url, height, width)
{
 window.open(url, 
'PopUpWindow''toolbar=no,directories=no,menubar=no,resizable=no,status=no,height=' + height + ',width=' + width);
}

Javascript sneakily pretends to support this - no script error - every time I called the function, the virtual root wasn't being added on. That's because Javascript doesn't support method overloading; it just uses the function which was defined last (thanks, Bertrand, for verifying my hunch). I had to give the second function a different name, and it all worked.

Here's an easy way to verify - this will show the second message:

<html>
<
head>
<
script>
function test(one,two)
{
alert('expected: first function with two parameters');
}

function test(one)
{
alert('surprise! second function with one parameter');
}
</script>
<
/head>
<
body onload="javascript:test('first','second')">
<
/body>

 

18 Comments

  • If you had only the first version, you could still call test(5), and the &quot;two&quot; variable would just be undefined, which you can test for.

  • Good point, Tyler. That's a better pattern.



    However, there are two issues here:

    1) Method overloading requires different strategies in Javascript. Your approach solves that.

    2) Programmers who are used to the overloading syntax of other languages (me, for example) are likely to run into trouble when they try this in Javascript. It's especially tricky because there's no compile error, just different behavior than expected.

  • Yeah, that's because you can pass any number of parameters to a javascript function and access them via the arguments collection. Javascript doesn't have a good method resolution strategy. It only takes the last one.



    function x()

    {

    alert(arguments[0]);

    alert(arguments[1]);

    }



    x(1,2);

  • You could use named arguments with the only parameter an object. Then just check for the existence of the named argument. You can even pass a function as an argument.



    &lt;html&gt;

    &lt;head&gt;

    &lt;script language=javascript&gt;

    function test(argTest)

    {

    'x' in argTest ? alert('x = ' + argTest.x) : alert('x does not exist');

    'y' in argTest ? alert('y = ' + argTest.y) : alert('y does not exist');

    'z' in argTest ? alert('z = ' + argTest.z) : alert('z does not exist');

    }



    function functest()

    {

    return 'this is from a function';

    }



    &lt;/script&gt;

    &lt;/head&gt;

    &lt;body&gt;

    &lt;button onclick=&quot;test({x:1, y:'two'});&quot;&gt;Test x,y&lt;/button&gt;&lt;br&gt;

    &lt;button onclick=&quot;var zarg='z arg'; test({z:zarg});&quot;&gt;Test z&lt;/button&gt;&lt;br&gt;

    &lt;button onclick=&quot;var f = functest(); test({x:f});&quot;&gt;Test function&lt;/button&gt;&lt;br&gt;

    &lt;/body&gt;

    &lt;/html&gt;

  • To pretend we can do overloading in javascript further, you can overload with parameters with different types using typeof and other tricks.



    I sometimes have functions that take a string or array as an argument. The function might look like this:



    function doStuff(arg1) {

    if (/string/.test(typeof(arg1))) {

    // do the string

    } else {

    // do the array

    }

    }



    Note that if you use typeof(array), you will end up with &quot;object&quot; as returned value. That's why you need other tricks, such as determine the object has a property called &quot;length&quot;.

  • Hi there,



    I have developed a javascript library (not published yet) where you can inject code at the beginning or end of an existing function. You could utilize it to be able to really overload a function by inserting an (if arguments[0] instanceof String &amp;&amp; arguments[1] instanceof Number ...) to execute only the code that should be run when certain parameters are passed. I will implement this so that you can do something like : myMethod.overloads(String, Number, Object, CustomClass, code);

  • Still i think it is possible

  • Just to point out responding to frogcoder - you should not test for an array by looking for a length property. After all, String objects (not to be confused with string literals) also have a type of Object and a length property.

    You can test for Array with a simple conditional:

    if (arg1 instanceof Array)
    {
    // Do something
    }

    Similarly, you should test for a string like this:

    if (typeof(arg1) == "string" || (arg1 instanceof String))
    {
    // Do something
    }

    This handles both string literals ("string") and String objects (new String("string")), which are interchangeable.

  • Really interestnig and informative!!:)

  • Umm... JavaScript doesn't pretend to support function overloading, it simply doesn't support it at all. I guess that the reason why you can respecify a function is solely due to the nature of the language: in browser side scripting, all attempts are often made to execute the code and thus such decisions are required to consolidate for common user errors. Besides, the ability to repurpose a function name is by itself a nice feature ;D

    And yes, I know I'm replying to a 5-year-old post :D

  • In fact, im suprised that someone as a Microsoft Most Valueable Professional posts this on a asp.net forums, clearly showing a complete lack of understanding what they are actually doing.

  • @Arjen - Did you notice the date on this post? It's 5 years old. I've learned a lot in the past 5 years, as I hope we all have.

  • 5 years old or not, it's still on the internet today, read by people who seek answers to their questions and maybe end up reading pages like this after using a search engine.

    The point I'm trying to make is that you should not make posts based on your own false assumptions, presenting it as the truth. Especially as an MVP. Because this way, you're not helping the community.

    If you know stuff, share it, if you don't, get to the bottom of it.

  • Arjen:

    No knowledge is absolute. All we can ever do is pretent to understand something..

    Jon:

    Thanks for sharing it IS helpful (even if it is 5 years old)..

  • Some good info on here =) I have a lot of build functions that take about 20 arguments so I finally decided to try and find a better way to set defaults and then only adjust what was necessary. Below is the basics of what I will be using and might be of some practical use to anybody else in the same situation. Essentially its a function that sets its defaults and then evals on the arguments array to change any of the presets.

    function f_start()
    {
    x();
    x(['vName','Cow']);
    x(['vWidth',90],['vHeight',200],['vName','Cow']);
    }

    function x()
    {
    var vWidth = 60;
    var vHeight = 80;
    var vName = 'Box';
    for(var i=0;i<arguments.length;i++)
    {
    eval(arguments[i][0] + ' = "' + arguments[i][1] + '";');
    }
    alert('Making a '+vName+' that is '+vWidth+' wide and '+vHeight+' high');
    }
    //Making a Box that is 60 wide and 80 high
    //Making a Cow that is 60 wide and 80 high
    //Making a Cow that is 90 wide and 200 high

  • yes you 100% right i have tested same.

  • A better way to handle sending 20 arguments to your function is to create a class with 20 properties. Then pass the newly instantiated object with your 20 properties/values to the method.

    function ThisMethodNeeds20Arguments(myNewObject)
    function NewClass() {
    this.property1
    ..
    this.property20
    }
    var instanceOfNewClass = new NewClass();
    instanceOfNewClass.property1 = "whatever";
    instanceOfNewClass.property2 = "more...";
    instanceOfNewClass.property3 = 3;
    instanceOfNewClass.property4 = false;
    ..
    instanceOfNewClass.property10 = { 1, 2, 3 };

  • Knowledge neve become old...

Comments have been disabled for this content.