26

I use method overloading as below in my Javascript code.

function somefunction()
{
    //1st function
}

function somefunction(a)
{
   //2nd function
}

function somefunction(a,b)
{
   //3rd function
}

somefunction(); // function call goes here

What I don't understand is if I call the somefunction() javascript should call the 1st function but the problem is javascript actually calls the 3rd function. Why is that? How can I call the 1st and 2nd function ? What is the reason for this? Is there a proper way to implement method overloading in Javascript? What's the industry standard?

Brian Tompsett - 汤莱恩
  • 5,753
  • 72
  • 57
  • 129
Techie
  • 44,706
  • 42
  • 157
  • 243

12 Answers12

46

JavaScript does not support method overloading (as in Java or similiar), your third function overwrites the previous declarations.

Instead, it supports variable arguments via the arguments object. You could do

function somefunction(a, b) {
    if (arguments.length == 0) { // a, b are undefined
        // 1st body
    } else if (arguments.length == 1) { // b is undefined
        // 2nd body
    } else if (arguments.length == 2) { // both have values
        // 3rd body
    } // else throw new SyntaxError?
}

You also could just check for typeof a == "undefined" etc, this would allow calling somefunction(undefined), where arguments.length is 1. This might allow easer calling with various parameters, e.g. when you have possibly-empty variables.

Bergi
  • 630,263
  • 148
  • 957
  • 1,375
  • How can I know that which parameter it is if only one parameter is passed to the function call..? Like `somefunction(something);` – Rohit Sharma Jan 04 '18 at 11:49
  • @RohitSharma If there's only one, it's the first. JavaScript does not support named parameters, it's only the order that matters. – Bergi Jan 04 '18 at 12:09
  • Then, how can I make the first parameter optional..? – Rohit Sharma Jan 04 '18 at 12:25
  • @RohitSharma You cannot. Of course you can call `someFunction(undefined, someValue)`. – Bergi Jan 04 '18 at 12:57
  • Just for clearance...! :) But, how jQuery's `on()` method works for different-different types of using with parameters. Like `.on('event','selector',callback)` or `.on('event',callback)`, we'r not passing undefined for optional parameter there..! – Rohit Sharma Jan 04 '18 at 13:15
  • @RohitSharma Yes, it distinguishes them by their type. If `arguments[1]` is a function, it'll be the `callback` and there is no selector. If `arguments[1]` is a string, it's the selector and `arguments[2]` must be the callback function. – Bergi Jan 04 '18 at 13:19
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/162517/discussion-between-rohit-sharma-and-bergi). – Rohit Sharma Jan 04 '18 at 13:23
9

JS will pass undefined to any parameters which are not provided. If you want something like overloading, you'll need to do something similar to the code below:

function someFunction(a, b) {
    if (typeof a === 'undefined') {
        // Do the 0-parameter logic
    } else if (typeof b === 'undefined') {
        // Do the 1-parameter logic
    } else {
        // Do the 2-parameter logic
    }
}
carlosfigueira
  • 85,035
  • 14
  • 131
  • 171
8

You're just erasing the variable somefunction with each new declaration.

This is equivalent to

   window.somefunction = function(...
   window.somefunction = function(...
   window.somefunction = function(...

Javascript doesn't offer method overloading.

The proper way is either :

  • to define the third function and to test what parameters are defined
  • to pass only one object containing the parameters (which isn't really different but is cleaner)
Denys Séguret
  • 372,613
  • 87
  • 782
  • 758
  • 1
    This answer is false. function somefunc(){ }; is to be compared to *var* somefunc = function() {}; As a proof, if you later declare function anotherFunction() { window.somefunc(); <--- undefined error } – GameAlchemist Jun 11 '14 at 11:18
4

You can't overload methods in JavaScript. In javascript, functions are stored in variables. Global variables are stored on the window object. You can only have one property per object with the same name (exclusive-key hash).

What you can do, is define the definition with the most parameters and check to see how many were passed in.

function Test(a, b, c)
{
    if(typeof a == 'undefined') 
    {
        a = 1;
    }

    if(typeof b == 'undefined') 
    {
        b = "hi";
    }

    if(typeof c == 'undefined') 
    {
        c = Date.Now;
    }
}

Now if I call Test(), it'll act as if I called Test(1, "hi", Date.Now)

Sheridan Bulger
  • 1,214
  • 7
  • 9
3

There is no real function overloading in JavaScript since it allows to pass any number of parameters of any type. the best practice would be to make a function like: myfunc(opt)

{
// with opt = {'arg1':'a1','arg2':2, etc}, then check your opt inside of the function
}
Frenchi In LA
  • 3,139
  • 3
  • 25
  • 41
3

I tried to develop an elegant solution to this problem described here. And you can find the demo here. The usage looks like this:

var out = def({
    'int': function(a) {
        alert('Here is int '+a);
    },

    'float': function(a) {
        alert('Here is float '+a);
    },

    'string': function(a) {
        alert('Here is string '+a);
    },

    'int,string': function(a, b) {
        alert('Here is an int '+a+' and a string '+b);
    },
    'default': function(obj) {
        alert('Here is some other value '+ obj);
    }

});

out('ten');
out(1);
out(2, 'robot');
out(2.5);
out(true);

The methods used to achieve this:

var def = function(functions, parent) {
 return function() {
    var types = [];
    var args = [];
    eachArg(arguments, function(i, elem) {
        args.push(elem);
        types.push(whatis(elem));
    });
    if(functions.hasOwnProperty(types.join())) {
        return functions[types.join()].apply(parent, args);
    } else {
        if (typeof functions === 'function')
            return functions.apply(parent, args);
        if (functions.hasOwnProperty('default'))
            return functions['default'].apply(parent, args);        
    }
  };
};

var eachArg = function(args, fn) {
 var i = 0;
 while (args.hasOwnProperty(i)) {
    if(fn !== undefined)
        fn(i, args[i]);
    i++;
 }
 return i-1;
};

var whatis = function(val) {

 if(val === undefined)
    return 'undefined';
 if(val === null)
    return 'null';

 var type = typeof val;

 if(type === 'object') {
    if(val.hasOwnProperty('length') && val.hasOwnProperty('push'))
        return 'array';
    if(val.hasOwnProperty('getDate') && val.hasOwnProperty('toLocaleTimeString'))
        return 'date';
    if(val.hasOwnProperty('toExponential'))
        type = 'number';
    if(val.hasOwnProperty('substring') && val.hasOwnProperty('length'))
        return 'string';
 }

 if(type === 'number') {
    if(val.toString().indexOf('.') > 0)
        return 'float';
    else
        return 'int';
 }

 return type;
};
stamat
  • 1,832
  • 21
  • 26
3

What I don't understand is if I call the somefunction() javascript should call the 1st function but the problem is javascript actually calls the 3rd function.

That is expected behavior.

Why is that ?

The issue is that JavaScript does NOT natively support method overloading. So, if it sees/parses two or more functions with a same names it’ll just consider the last defined function and overwrite the previous ones.

Why is that ? How can I call the 1st and 2nd function ? What is the reason for this?

One of the way I think is suitable for most of the case is follows -

Lets say you have method

function foo(x)
{
} 

Instead of overloading method which is not possible in javascript you can define a new method

fooNew(x,y,z)
{
}

and then modify the 1st function as follows -

function foo(x)
{
  if(arguments.length==2)
  {
     return fooNew(arguments[0],  arguments[1]);
  }
} 

If you have many such overloaded method consider using switch than just if-else statements.

Is there a proper way to do the method overloading ? What's the industry standard ?

There is no standard as such or an more proven method to do method overloading in javascript. One should do what best suits their programming design. I would say simple switch on arguments length with checking type that it is not undefined should suffice.

Aniket Thakur
  • 66,731
  • 38
  • 279
  • 289
2

arguments object are used to create a method overloading like concept.

arguments is a special type of object that's only available inside the functions execution context.

arguments.length property is used to identify the number of parameters passed into the function.

You can make the better use of first class functions to create fake method overloading. The full concept is explained on my own website: Overload Functions in JavaScript

TylerH
  • 20,799
  • 66
  • 75
  • 101
Nithya Rajan
  • 4,722
  • 19
  • 30
1

Method overloading is not directly supported in JavaScript. Here is an example how you can achieve something very much like it as shown below:

function overloadMethod(object, name, fn){

            if(!object._overload){
            object._overload = {};
            }

            if(!object._overload[name]){
            object._overload[name] = {};
            }

            if(!object._overload[name][fn.length]){
            object._overload[name][fn.length] = fn;
            }

              object[name] = function() {
                        if(this._overload[name][arguments.length])
                        return this._overload[name][arguments.length].apply(this, arguments);
              };
}

function Students(){
  overloadMethod(this, "find", function(){
            // Find a student by name
  });

  overloadMethod(this, "find", function(first, last){
            // Find a student by first and last name
  });

}

var students = new Students();
students.find(); // Finds all
students.find("Rahul"); // Finds students by name
students.find("Rahul", "Mhatre"); // Finds users by first and last name

source: source

mamosek
  • 316
  • 2
  • 6
0

If you use classes you create two different classes which have the same method with different parameters. Then you can use spread operator along with dependency injection to mimic the overloading behavior.

class Foo{
  method(){
    console.log('hello from method foo')
  }
}

class Bar{
  method(name){
    console.log(`hello from method bar. Name is ${name}`) 
  }
}

function MimicOverload(obj, options){
    obj.method(...options)  
}

const obj1 = new Foo()
const obj2 = new Bar()


MimicOverload(obj1,[])
MimicOverload(obj2,['overloaded'])
jbe90
  • 1
0

I tinkered with this and was able to make this work against custom classes without much trouble.

let overloadTest = overload(
    [String], function(value) {
        console.log('we got a string', value);
    },
    [Number], function(value) {
        console.log('we got a number', value);
    },
    [String, Number], function(s, n) {
        console.log('we got a string AND a number', s, n);
    }
    [MyCustomClass], function(value) {
        console.log('we got a MyCustomClass instance', value);
    }
);

With this overload implementation:

function overload(...overloads) {
    const f = function(...args) {
        let constructorArray = args.map(arg => arg.constructor);
        let implIndex = f.overloads.findIndex(sig => {
            return constructorArray.length === sig.length &&
                constructorArray.every((o,i) => o === sig[i])
            ;
        }) + 1;
        if (implIndex > 0 && typeof(f.overloads[implIndex]) === 'function') {
            return f.overloads[implIndex].apply({}, args);
        } else {
            const message = "There is no implementation that matches the provided arguments.";
            console.error(message, constructorArray);
            throw Error(message);
        }
    };
    f.overloads = overloads;
    return f;
};

This doesn't work on instance methods just yet. But, it could be extended.

Also, the arguments list refers directly to constructors (as opposed to a strings), which means you could extend with additional validation if you like -- for example, ensuring that each argument type is actually a function/constructor at overload() time. You could also conceivably create a version of overload() that performs DI.

svidgen
  • 13,744
  • 4
  • 33
  • 58
0

I think that can't be considered method overloading, but it's a alternative to use one function to diferent combinations of parameters. The function's parameter need to be an object.

function something(obj){
   if(obj.a != undefined){
      return a*a;
   }
   if((obj.b != undefined)&&(obj.c != undefined)){
      return b*c;
   }
}