Question

Check this fiddle or the code below:

 function abc(s) {
     console.log('in abc(s)');
 }

 function abc(s, t) {
     console.log('in abc(s,t)');
 }

 abc('1');

The output of this question is always in abc(s,t)

Can someone please explain me whats going on here and why ?

Was it helpful?

Solution 2

First, no method overload support in JavaScript (see @6502 workaround).

Second, to describe what you're experiencing, in JavaScript, the last declared function (with the same name) is invoked because the former has been overwritten, It relates to JavaScript Hoisting.

Try to reorder the functions declarations and see the output result again:

 function abc(s, t) {
     console.log('in abc(s,t)');
 }

function abc(s) {
     console.log('in abc(s)');
 }

 abc('1');

OTHER TIPS

In Javascript there is no overload concept.

You can however write a function that checks how many arguments have been passed by using the arguments value.

function foo(s, t) {
    if (arguments.length == 2) {
        ...
    } else {
        ...
    }
}

all arguments that the function expects in the signature but that are not passed by the caller are received as undefined. You can also write variadic functions by simply accessing the n-th argument passed with arguments[i]. Note however that arguments is not a Javascript array, so not all array methods are available for it.

About being able to redefine the same function multiple times without errors things are a bit complex to explain because the rules are strange.

A simple explanation is you could think of is that function is an executable statement like it is in Python and so the last function definition wins. This would be wrong however because, differently from Python, the following is legal Javascript code:

console.log(square(12));
function square(x) { return x*x; }

i.e. you can call a function in lines that are preceding the definition (in a script: of course typing those two lines in a Javascript console wouldn't work).

A slightly more correct explanation is that the compiler first parses all the function definitions (last wins) and then starts executing the code. This mental model works if you don't put functions inside if because what happens in practice in that case is implementation dependent (and I'm not talking about crazy IE, but even that FF and Chrome will do different things). Just don't do that.

You can even use the form

var square = function(x) { return x*x; }

and in this case it's a simple assignment of a "function expression" to a variable that is executed when the flow passed through it (so it's ok to place different implementations of a function inside different if branches, but you cannot call the function before assigning it an implementation).

In javascript, there is only one function with any given name and if multiple functions with the same name are declared, the last one declared will be the one that is active.

You can however test the arguments that are passed to your function and implement many of the same types of behaviors that function overloading is designed to handle. In fact, in some cases you can do even more.

In your specific example:

function abc(s, t) {
    // test to see if the t argument was passed
    if (t !== undefined) {
       console.log('was called as abc(s,t)');
    } else {
       console.log('was called as abc(s)');
    }
}

abc('1');       // outputs 'was called as abc(s)'
abc('1', '2');  // outputs 'was called as abc(s,t)'

But, you can also get much, much more creative (and useful).

For example, the jQuery .css() method can be called five different ways.

.css( propertyName )
.css( propertyNames )
.css( propertyName, value )
.css( propertyName, function(index, value) )
.css( properties )

The code inside the .css() method examines the type and number of the arguments to figure out which way it is being called and therefore exactly what operation to carry out.

Let's look at how this could be done to figure out which of the 5 forms of this function are being used:

css: function(prop, value) {
    // first figure out if we only have one argument
    if (value === undefined) {
        if (typeof prop === "string") {
            // we have a simple request for a single css property by string name
            // of this form: .css( propertyName )
        } else if (Array.isArray(prop)) {
           // we have a request for an array of properties
           // of this form: .css( propertyNames )

        } else if (typeof prop === "object") {
           // property-value pairs of css to set
           // of this form: .css( properties )
        }
    } else {
        if (typeof value === "function") {
           // of this form: .css( propertyName, function(index, value) )
        } else {
           // of this form: .css( propertyName, value )
        }
    }
}

You can also implement optional arguments. For example, jQuery's .hide() can accept many forms. One of the forms is .hide( [duration ] [, complete ] ) where both the duration and the completion function are optional. You can pass nothing, just a duration or both a duration and completion callback function. That could be implemented like this:

 hide: function(duration, fn) {
     // default the duration to zero if not present
     duration = duration || 0;
     // default the completion function to a dummy function if not present
     fn = fn || function() {};

     // now the code can proceed knowing that there are valid arguments for both
     // duration and fn whether they were originally passed or not
 }

I find one of the most useful ways of using these variable arguments are to allow code to support a variety of different argument types so that no matter what state your arguments are in, you can just pass them as you have them without having to convert them to some universal type. For example, in this implementation of a set object in javascript, the .add() method can take all of these different forms of arguments:

s.add(key)
s.add(key1, key2, key3)
s.add([key1, key2, key3])
s.add(key1, [key8, key9], key2, [key4, key5])
s.add(otherSet)              // any other set object
s.add(arrayLikeObject)       // such as an HTMLCollection or nodeList

This both accepts a variable number of arguments and it accepts a number of different types for each argument and it will adapt based on what is passed to it. So, you can initialize a set via a list of keys, an array of keys, from another set, from a pseudo array or any mixture of those types. Internally, the code just iterates through each argument that was passed to the function, checks the type of the argument and acts accordingly.

You can see the code here on GitHub for further info on how this is done.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top