901

What is the best way(s) to fake function overloading in Javascript?

I know it is not possible to overload functions in Javascript as in other languages. If I needed a function with two uses foo(x) and foo(x,y,z) which is the best / preferred way:

  1. Using different names in the first place
  2. Using optional arguments like y = y || 'default'
  3. Using number of arguments
  4. Checking types of arguments
  5. Or how?
hamdiakoguz
  • 15,795
  • 9
  • 33
  • 27
  • 21
    Perhaps it would be useful to ask why you think you need function overloading to begin with. I think that will get us closer to a real solution. – Breton Jan 19 '09 at 00:41
  • 1
    This is closed, but I do the following: this.selectBy = { instance: selectByInstance, // Function text: selectByText, // Function value: selectByValue // Function }; – Prisoner ZERO Jun 22 '12 at 20:46
  • My answer shows how to do run time function overloading, it has a speed penalty and I wouldn't advise doing it to get around Javascript's specification. Function overloading is really a compile time task, I only provide the answer for academic purposes and leave it up to your own discretion as to whether or not to employ it in code. – Keldon Alleyne Oct 23 '12 at 22:57
  • 2
    Just in case it is useful, I've built a lightweight js framework that allows for type-based method overloading. Obviously the same caveats apply with regards to performance, but it's worked well for my needs so far and still has quite a lot of room for improvement: http://blog.pebbl.co.uk/2013/01/describejs.html#methodoverloading – Pebbl Jan 15 '13 at 00:24
  • Closed because it's opinion based, and yet it has 871 upvotes. That means something – user121330 Jun 02 '22 at 17:11

37 Answers37

713

The best way to do function overloading with parameters is not to check the argument length or the types; checking the types will just make your code slow and you have the fun of Arrays, nulls, Objects, etc.

What most developers do is tack on an object as the last argument to their methods. This object can hold anything.

function foo(a, b, opts) {
  // ...
  if (opts['test']) { } //if test param exists, do something.. 
}


foo(1, 2, {"method":"add"});
foo(3, 4, {"test":"equals", "bar":"tree"});

Then you can handle it anyway you want in your method. [Switch, if-else, etc.]

S.Serpooshan
  • 7,608
  • 4
  • 33
  • 61
epascarello
  • 204,599
  • 20
  • 195
  • 236
  • Any suggestions on using this pattern with a callback? http://stackoverflow.com/questions/9831027/javascript-overloading-with-a-callback – Unpossible Mar 23 '12 at 14:57
  • 45
    Could you provide a sample implementation of foo() that illustrates how these "opts" parameters are used/referenced? – Moe Howard Mar 28 '12 at 23:23
  • 24
    Moe// It could be like this; `if(opts['test']) //if test param exists, do something.. if(opts['bar']) //if bar param exists, do something` – Deckard Nov 09 '12 at 13:07
  • 94
    This isn't function overloading. Function overloading is having two separate functions with the same name but different parameters. What you're describing is just one function with an object argument at the end. – d512 Mar 05 '13 at 03:13
  • 73
    @user1334007 it is impossible to have function overloading like you would do it in Java/.NET. Yes this is not "exactly" overloading, but it does the job. – epascarello Mar 05 '13 at 03:24
  • one thing is fine that js doesnt suports function overloading..thanx for dat clarity – saidesh kilaru May 09 '13 at 14:19
  • 20
    I'm surprised nobody has asked this already: why is checking `arguments.length` not recommended? Also, I've been here before and read _What most developers do is..._, but I'm sure this is the only place I've seen that done. That method also spoils the syntactic sugaryness of having 'overloads'! – c24w Jul 03 '13 at 10:37
  • 6
    @c24w Yes you could check lengthm, but it would fail in causes like (obj, str, str) vs (obj, str, bool). – epascarello Jul 03 '13 at 12:52
  • 1
    @epascarello: ah, so there's no suggestion that `arguments.length` is a bad solution, just that in certain cases you'll have to fall back to checking types (which isn't ideal). Gotcha! – c24w Jul 03 '13 at 13:11
  • 1
    This makes it hard to document to the outside world what this function accepts as variables. I would not use this. – Dorian Jun 17 '14 at 15:48
  • 2
    @Dorian You can not comment it or use JSDoc? – epascarello Jun 17 '14 at 18:55
  • Your options are you sniff types or you have an object with defined settings. Problem with types is any two the signatures can not be the same. jQuery does type sniffing with its methods. – epascarello Jun 17 '14 at 19:06
  • 6
    @Dorian Using option objects is how a vast number of JS libraries do it-your (ahem) options are limited. – Dave Newton Aug 01 '14 at 21:04
  • 8
    "checking the types will just make your code slow" Relatively speaking, creating an object to then lookup properties in is far slower than type checking. If the object passed already exists then yes the property lookup on it will most likely be faster. http://jsperf.com/type-check-vs-property-lookup The code in this answer creates a new object with each call which is inherently slower than type checking. – ReenignE Aug 25 '14 at 21:53
  • 2
    one technique (which will **deliberately** except on unsupported types) is to have a thin wrapper around an object with type specific functions, using typeof parameter(s) as the key. eg `var thing_handlers={ string : function(x){ return x;}, number : function(x) {return x+25; } }; function do_thing(x) {return thing_handlers[typeof x](x);}` this is both fast, polymorphic, and most importantly, crashes at runtime to force developer to write safe(r) code. – unsynchronized Jul 23 '16 at 00:13
196

I often do this:

C#:

public string CatStrings(string p1)                  {return p1;}
public string CatStrings(string p1, int p2)          {return p1+p2.ToString();}
public string CatStrings(string p1, int p2, bool p3) {return p1+p2.ToString()+p3.ToString();}

CatStrings("one");        // result = one
CatStrings("one",2);      // result = one2
CatStrings("one",2,true); // result = one2true

JavaScript Equivalent:

function CatStrings(p1, p2, p3)
{
  var s = p1;
  if(typeof p2 !== "undefined") {s += p2;}
  if(typeof p3 !== "undefined") {s += p3;}
  return s;
};

CatStrings("one");        // result = one
CatStrings("one",2);      // result = one2
CatStrings("one",2,true); // result = one2true

This particular example is actually more elegant in javascript than C#. Parameters which are not specified are 'undefined' in javascript, which evaluates to false in an if statement. However, the function definition does not convey the information that p2 and p3 are optional. If you need a lot of overloading, jQuery has decided to use an object as the parameter, for example, jQuery.ajax(options). I agree with them that this is the most powerful and clearly documentable approach to overloading, but I rarely need more than one or two quick optional parameters.

EDIT: changed IF test per Ian's suggestion

rocketsarefast
  • 4,072
  • 1
  • 24
  • 18
  • 20
    Parameters which are not specified are `undefined` in JS, not `null`. As a best practice, you should never set anything to `undefined`, so it should not be a problem as long as you change your test to `p2 === undefined`. – Tamzin Blake Aug 31 '12 at 17:49
  • 3
    If you pass `false` as the last argument then it won't concatenate `"false"` to the end, because the `if(p3)` won't branch. – dreamlax Oct 23 '12 at 05:50
  • 1
    Or the more popular `typeof p2 === "undefined"` – Ian Nov 05 '12 at 15:14
  • Thanks for that! I too am familiar with the pattern you mentioned (used in various C family languages). Didn't work in javascript. Was looking for a fix. Your solution worked nicely! +1 :-) – iPadDeveloper2011 Feb 22 '13 at 06:57
  • 6
    Just a quick note, your `typeof p2 === "undefined"` is probably the reverse of what you're expecting in the instance of your example, I think `typeof p2 !== "undefined"` is what you intended. Also, May I suggest being its supposed to concatenate string, number, and boolean that you actually do `p2 === "number"; p3 === "boolean"` – WillFM Apr 23 '13 at 02:56
  • you could use `p2 !== void 0` for a less verbose comparison – bevacqua Nov 11 '13 at 17:05
  • 9
    I like doing this: p3 = p3 || 'default value'; – Dorian Jun 17 '14 at 15:46
  • 3
    What is the meaning of `===` and `!==`? Why not just use `==` and `!=`? – Ricardo Magalhães Cruz Mar 02 '16 at 19:41
  • This could be improved with arguments, and a more modern approach could use rest params, concat and join – Mild Fuzz Mar 08 '17 at 10:43
  • 1
    Just a quick note to your C# code. Calling ToString is not needed when you concatenate objects using the concatenation operator (+). – Stack0verflow Apr 13 '17 at 15:27
  • 1
    I think, this one should be an accepted answer. It is very straightforward to check for the arguments as undefined as opposed to passing an extra dummy object in the argument list. – Aamir Jul 21 '17 at 03:08
  • 1
    @Dorian, p3 = p3 || 'default value' isn't advised, because if you pass false as an intended value, then your false will be converted to your default value, should always test for undefined. – user678415 Mar 31 '18 at 00:17
  • @TamzinBlake theoretically, you are right. pratically having "null" is already an issue in many languages. Having to deal with "null" and "undefined" at the same time is super annoying in javascript – Welcor May 26 '23 at 21:52
118

There is no real function overloading in JavaScript since it allows to pass any number of parameters of any type. You have to check inside the function how many arguments have been passed and what type they are.

Knu
  • 14,806
  • 5
  • 56
  • 89
Gumbo
  • 643,351
  • 109
  • 780
  • 844
  • 2
    John Resig (of jQuery) once tried this, but the attempt was purely academic and didn't provide any real benefit. – scunliffe Jan 19 '09 at 00:38
  • 18
    John Resig's function overload here http://ejohn.org/blog/javascript-method-overloading/ – Terrance May 26 '11 at 20:45
  • @Terrance: I like Resig's method too. It works like a charm. I just need to find a way to create a test for it to validate use cases. – chrisvillanueva Jun 28 '13 at 03:38
  • 1
    "This function won’t change the world, but it’s short, concise, and uses an obscure JavaScript feature – so it wins in my book." :-) – Frerich Raabe May 31 '18 at 06:44
107

The correct answer is THERE IS NO OVERLOADING IN JAVASCRIPT.

Checking / Switching inside the function is not OVERLOADING.

The concept of overloading: In some programming languages, function overloading or method overloading is the ability to create multiple methods of the same name with different implementations. Calls to an overloaded function will run a specific implementation of that function appropriate to the context of the call, allowing one function call to perform different tasks depending on context.

For example, doTask() and doTask(object O) are overloaded methods. To call the latter, an object must be passed as a parameter, whereas the former does not require a parameter, and is called with an empty parameter field. A common error would be to assign a default value to the object in the second method, which would result in an ambiguous call error, as the compiler wouldn't know which of the two methods to use.

https://en.wikipedia.org/wiki/Function_overloading

All suggested implementations are great, but truth to be told, there is no native implementation for JavaScript.

Marco
  • 2,757
  • 1
  • 19
  • 24
  • 11
    finally a normal answer! THERE IS NO OVERLOADING IN JAVASCRIPT. – Razvan Tudorica Nov 19 '19 at 21:31
  • 32
    OP asked for a way to *fake* overloading. – Ateur Games Dec 13 '19 at 21:30
  • 3
    As i did say before, we are here do educate people, we don't just give answers to them without verifying that what they are asking is right. – Marco Dec 16 '19 at 11:54
  • 5
    Arguing with a human about the literal meaning when you should focus on the intended meaning is just as misplaced as arguing with a compiler about your intended meaning when it only responds to the literal meaning of your code. The OP's purpose was clearly to achieve a similar effect across call sites as overloading provides while acknowledging JS does not support the construct. – Chris Mountford Jul 23 '21 at 03:08
  • Well 87 people upvoted, ao there's that. Emulate a feature like that is just a waste of time. You like it or not, JavaScript doesn't have this feature so people should know. – Marco Jul 24 '21 at 04:07
27

There are two ways you could approach this better:

  1. Pass a dictionary (associative array) if you want to leave a lot of flexibility

  2. Take an object as the argument and use prototype based inheritance to add flexibility.

t3rse
  • 10,024
  • 11
  • 57
  • 84
  • 1
    this was my initial thought, however, if the function you are creating is to be used in a library or by others, enumerating the values plainly can be helpful – roberthuttinger Dec 07 '12 at 14:19
22

Here is an approach that allows real method overloading using parameter types, shown below:

Func(new Point());
Func(new Dimension());
Func(new Dimension(), new Point());
Func(0, 0, 0, 0);

Edit (2018): Since this was written in 2011, the speed of direct method calls has greatly increased while the speed of overloaded methods have not.

It is not an approach I would recommend, but it is a worthwhile thought exercise to think about how you can solve these types of problems.


Here is a benchmark of the different approaches - https://jsperf.com/function-overloading. It shows that function overloading (taking types into account) can be around 13 times slower in Google Chrome's V8 as of 16.0(beta).

As well as passing an object (i.e. {x: 0, y: 0}), one can also take the C approach when appropriate, naming the methods accordingly. For example, Vector.AddVector(vector), Vector.AddIntegers(x, y, z, ...) and Vector.AddArray(integerArray). You can look at C libraries, such as OpenGL for naming inspiration.

Edit: I've added a benchmark for passing an object and testing for the object using both 'param' in arg and arg.hasOwnProperty('param'), and function overloading is much faster than passing an object and checking for properties (in this benchmark at least).

From a design perspective, function overloading is only valid or logical if the overloaded parameters correspond to the same action. So it stands to reason that there ought to be an underlying method that is only concerned with specific details, otherwise that may indicate inappropriate design choices. So one could also resolve the use of function overloading by converting data to a respective object. Of course one must consider the scope of the problem as there's no need in making elaborate designs if your intention is just to print a name, but for the design of frameworks and libraries such thought is justified.

My example comes from a Rectangle implementation - hence the mention of Dimension and Point. Perhaps Rectangle could add a GetRectangle() method to the Dimension and Point prototype, and then the function overloading issue is sorted. And what about primitives? Well, we have argument length, which is now a valid test since objects have a GetRectangle() method.

function Dimension() {}
function Point() {}

var Util = {};

Util.Redirect = function (args, func) {
  'use strict';
  var REDIRECT_ARGUMENT_COUNT = 2;

  if(arguments.length - REDIRECT_ARGUMENT_COUNT !== args.length) {
    return null;
  }

  for(var i = REDIRECT_ARGUMENT_COUNT; i < arguments.length; ++i) {
    var argsIndex = i-REDIRECT_ARGUMENT_COUNT;
    var currentArgument = args[argsIndex];
    var currentType = arguments[i];
    if(typeof(currentType) === 'object') {
      currentType = currentType.constructor;
    }
    if(typeof(currentType) === 'number') {
      currentType = 'number';
    }
    if(typeof(currentType) === 'string' && currentType === '') {
      currentType = 'string';
    }
    if(typeof(currentType) === 'function') {
      if(!(currentArgument instanceof currentType)) {
        return null;
      }
    } else {
      if(typeof(currentArgument) !== currentType) {
        return null;
      }
    } 
  }
  return [func.apply(this, args)];
}

function FuncPoint(point) {}
function FuncDimension(dimension) {}
function FuncDimensionPoint(dimension, point) {}
function FuncXYWidthHeight(x, y, width, height) { }

function Func() {
  Util.Redirect(arguments, FuncPoint, Point);
  Util.Redirect(arguments, FuncDimension, Dimension);
  Util.Redirect(arguments, FuncDimensionPoint, Dimension, Point);
  Util.Redirect(arguments, FuncXYWidthHeight, 0, 0, 0, 0);
}

Func(new Point());
Func(new Dimension());
Func(new Dimension(), new Point());
Func(0, 0, 0, 0);
Keldon Alleyne
  • 2,103
  • 16
  • 23
18

If I needed a function with two uses foo(x) and foo(x,y,z) which is the best / preferred way?

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.

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(arguments)
{
  if(arguments.length==2)
  {
     return fooNew(arguments[0],  arguments[1]);
  }
} 

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

kmoser
  • 8,780
  • 3
  • 24
  • 40
Aniket Thakur
  • 66,731
  • 38
  • 279
  • 289
17

The best way really depends on the function and the arguments. Each of your options is a good idea in different situations. I generally try these in the following order until one of them works:

  1. Using optional arguments like y = y || 'default'. This is convenient if you can do it, but it may not always work practically, e.g. when 0/null/undefined would be a valid argument.

  2. Using number of arguments. Similar to the last option but may work when #1 doesn't work.

  3. Checking types of arguments. This can work in some cases where the number of arguments is the same. If you can't reliably determine the types, you may need to use different names.

  4. Using different names in the first place. You may need to do this if the other options won't work, aren't practical, or for consistency with other related functions.

Matthew Crumley
  • 101,441
  • 24
  • 103
  • 129
12

Not everybody knows that you can do Destructuring assignment directly in a function signature.

Thanks to that you can easily define a very flexible method signature, which is, IMHO, superior to Java method overloading.

Example:

const myFunction = (({a, b, c}) => {
    console.log(a, b, c);
});

myFunction({a: 1, b: 2});
myFunction({a: 1, b: 2, c: 3});

You don't even need to respect the order of the parameters, and there is naming consistency between the calling statement and the target method signature.

You can also assign default values:

const myFunction = (({a = 1, b = 2, c} = {}) => {
    console.log(a, b, c);
});
Luca Fagioli
  • 12,722
  • 5
  • 59
  • 57
  • How would you go about defining function bodies for the concrete kind of input? Say you only have a and b, would you check whether or not c === undefined? – Lukas Süsslin Mar 09 '23 at 11:08
  • Yes, that's the only way. This approach does not represents a real function overloading, because in JavaScript you can have only one body for a named function. But at least it solves the hassle to have to write something like `myFunction(undefined, undefined, myParameter)` and also from checking the parameters order. – Luca Fagioli Mar 09 '23 at 11:53
11

I'm not sure about best practice, but here is how I do it:

/*
 * Object Constructor
 */
var foo = function(x) {
    this.x = x;
};

/*
 * Object Protoype
 */
foo.prototype = {
    /*
     * f is the name that is going to be used to call the various overloaded versions
     */
    f: function() {

        /*
         * Save 'this' in order to use it inside the overloaded functions
         * because there 'this' has a different meaning.
         */   
        var that = this;  

        /* 
         * Define three overloaded functions
         */
        var f1 = function(arg1) {
            console.log("f1 called with " + arg1);
            return arg1 + that.x;
        }

        var f2 = function(arg1, arg2) {
             console.log("f2 called with " + arg1 + " and " + arg2);
             return arg1 + arg2 + that.x;
        }

        var f3 = function(arg1) {
             console.log("f3 called with [" + arg1[0] + ", " + arg1[1] + "]");
             return arg1[0] + arg1[1];
        }

        /*
         * Use the arguments array-like object to decide which function to execute when calling f(...)
         */
        if (arguments.length === 1 && !Array.isArray(arguments[0])) {
            return f1(arguments[0]);
        } else if (arguments.length === 2) {
            return f2(arguments[0], arguments[1]);
        } else if (arguments.length === 1 && Array.isArray(arguments[0])) {
            return f3(arguments[0]);
        }
    } 
}

/* 
 * Instantiate an object
 */
var obj = new foo("z");

/*
 * Call the overloaded functions using f(...)
 */
console.log(obj.f("x"));         // executes f1, returns "xz"
console.log(obj.f("x", "y"));    // executes f2, returns "xyz"
console.log(obj.f(["x", "y"]));  // executes f3, returns "xy"
chessweb
  • 4,613
  • 5
  • 27
  • 32
7

I just tried this, maybe it suits your needs. Depending on the number of the arguments, you can access a different function. You initialize it the first time you call it. And the function map is hidden in the closure.

TEST = {};

TEST.multiFn = function(){
    // function map for our overloads
    var fnMap = {};

    fnMap[0] = function(){
        console.log("nothing here");
        return this;    //    support chaining
    }

    fnMap[1] = function(arg1){
        //    CODE here...
        console.log("1 arg: "+arg1);
        return this;
    };

    fnMap[2] = function(arg1, arg2){
        //    CODE here...
        console.log("2 args: "+arg1+", "+arg2);
        return this;
    };

    fnMap[3] = function(arg1,arg2,arg3){
        //    CODE here...
        console.log("3 args: "+arg1+", "+arg2+", "+arg3);
        return this;
    };

    console.log("multiFn is now initialized");

    //    redefine the function using the fnMap in the closure
    this.multiFn = function(){
        fnMap[arguments.length].apply(this, arguments);
        return this;
    };

    //    call the function since this code will only run once
    this.multiFn.apply(this, arguments);

    return this;    
};

Test it.

TEST.multiFn("0")
    .multiFn()
    .multiFn("0","1","2");
AntouanK
  • 4,880
  • 1
  • 21
  • 26
7

INTRODUCTION

So far reading through so many answers would give anyone a headache. Anyone trying to know the concept would need to know the following prerequisites.

Function overloading Definition, Function Length property, Function argument property

Function overloading in its simplest form means that a function performs different tasks on the basis of number of arguments that are being passed to it. Notably the TASK1, TASK2 and TASK3 are highlighted below and are being performed on the basis of the number of arguments being passed to the same function fooYo.

// if we have a function defined below
function fooYo(){
     // do something here
}
// on invoking fooYo with different number of arguments it should be capable to do different things

fooYo();  // does TASK1
fooYo('sagar'); // does TASK2
fooYo('sagar','munjal'); // does TAKS3

NOTE - JS does not provide inbuilt ability of function overloading.

Alternative

John E Resig (creator of JS) has pointed out an alternative which uses the above prerequisites to achieve the ability to implement function overloading.

The code below uses a straightforward but naive approach by using if-else or switch statement.

  • evaluates the argument-length property.
  • different values result in invocation of different functions.

var ninja = {
  whatever: function() {
       switch (arguments.length) {
         case 0:
           /* do something */
           break;
         case 1:
           /* do something else */
           break;
         case 2:
           /* do yet something else */
           break;
       //and so on ...
    } 
  }
}

Another technique is much more clean and dynamic. The highlight of this technique is the addMethod generic function.

  • we define a function addMethod which is used to add different functions to an object with the same name but different functionalities.

  • below the addMethod function accepts three params object name object, function name name and the function that we want to be invoked fn.

  • Inside addMethod definition var old stores the reference to the previous function being stored by the help of closure - a protective bubble.

function addMethod(object, name, fn) {
  var old = object[name];
  object[name] = function(){
    if (fn.length == arguments.length)
      return fn.apply(this, arguments)
    else if (typeof old == 'function')
      return old.apply(this, arguments);
  };
};
  • use debugger to understand the code flow.
  • below the addMethod adds three functions which when invoked using ninja.whatever(x) with the number of arguments x which can be anything i.e. either blank or one or more than one invokes different functions as defined while making use of the addMethod function.

var ninja = {};
debugger;


addMethod(ninja,'whatever',function(){ console.log("I am the one with ZERO arguments supplied") });
addMethod(ninja,'whatever',function(a){ console.log("I am the one with ONE arguments supplied") });
addMethod(ninja,'whatever',function(a,b){ console.log("I am the one with TWO arguments supplied") });


ninja.whatever();
ninja.whatever(1,2);
ninja.whatever(3);
Sagar Munjal
  • 762
  • 11
  • 12
5

Since JavaScript doesn't have function overload options object can be used instead. If there are one or two required arguments, it's better to keep them separate from the options object. Here is an example on how to use options object and populated values to default value in case if value was not passed in options object.

    function optionsObjectTest(x, y, opts) {
        opts = opts || {}; // default to an empty options object

        var stringValue = opts.stringValue || "string default value";
        var boolValue = !!opts.boolValue; // coerces value to boolean with a double negation pattern
        var numericValue = opts.numericValue === undefined ? 123 : opts.numericValue;

        return "{x:" + x + ", y:" + y + ", stringValue:'" + stringValue + "', boolValue:" + boolValue + ", numericValue:" + numericValue + "}";

}

here is an example on how to use options object

Subodh Ghulaxe
  • 18,333
  • 14
  • 83
  • 102
Vlad Bezden
  • 83,883
  • 25
  • 248
  • 179
4

Another way to approach this is by using the special variable: arguments, this is an implementation:

function sum() {
    var x = 0;
    for (var i = 0; i < arguments.length; ++i) {
        x += arguments[i];
    }
    return x;
}

so you can modify this code to:

function sum(){
    var s = 0;
    if (typeof arguments[0] !== "undefined") s += arguments[0];
.
.
.
    return s;
}
AustinWBryan
  • 3,249
  • 3
  • 24
  • 42
4

There is no way to function overloading in javascript. So, I recommend like the following by typeof() method instead of multiple function to fake overloading.

function multiTypeFunc(param)
{
    if(typeof param == 'string') {
        alert("I got a string type parameter!!");
     }else if(typeof param == 'number') {
        alert("I got a number type parameter!!");
     }else if(typeof param == 'boolean') {
        alert("I got a boolean type parameter!!");
     }else if(typeof param == 'object') {
        alert("I got a object type parameter!!");
     }else{
        alert("error : the parameter is undefined or null!!");
     }
}

Good luck!

Sean Vieira
  • 155,703
  • 32
  • 311
  • 293
Smith Lee
  • 340
  • 2
  • 9
4

check this out. It is very cool. http://ejohn.org/blog/javascript-method-overloading/ Trick Javascript to allow you to do calls like this:

var users = new Users();
users.find(); // Finds all
users.find("John"); // Finds users by name
users.find("John", "Resig"); // Finds users by first and last name
Jaider
  • 14,268
  • 5
  • 75
  • 82
  • Hi Jaider, check out my answer, it contains code for *actual* javascript method overloading. I'm talking `Func(new Point())` and `Func(new Rectangle())` will execute different functions. But I must point out that this is a dirty hack, since method overloading is really a compile time task not run time. – Keldon Alleyne Oct 23 '12 at 22:51
3

#Forwarding Pattern => the best practice on JS overloading Forward to another function which name is built from the 3rd & 4th points :

  1. Using number of arguments
  2. Checking types of arguments
window['foo_'+arguments.length+'_'+Array.from(arguments).map((arg)=>typeof arg).join('_')](...arguments)

#Application on your case :

 function foo(...args){
          return window['foo_' + args.length+'_'+Array.from(args).map((arg)=>typeof arg).join('_')](...args);

  }
   //------Assuming that `x` , `y` and `z` are String when calling `foo` . 
  
  /**-- for :  foo(x)*/
  function foo_1_string(){
  }
  /**-- for : foo(x,y,z) ---*/
  function foo_3_string_string_string(){
      
  }

#Other Complex Sample :

      function foo(...args){
          return window['foo_'+args.length+'_'+Array.from(args).map((arg)=>typeof arg).join('_')](...args);
       }

        /** one argument & this argument is string */
      function foo_1_string(){

      }
       //------------
       /** one argument & this argument is object */
      function foo_1_object(){

      }
      //----------
      /** two arguments & those arguments are both string */
      function foo_2_string_string(){

      }
       //--------
      /** Three arguments & those arguments are : id(number),name(string), callback(function) */
      function foo_3_number_string_function(){
                let args=arguments;
                  new Person(args[0],args[1]).onReady(args[3]);
      }
     
       //--- And so on ....   
Abdennour TOUMI
  • 87,526
  • 38
  • 249
  • 254
3

You can now do function overloading in ECMAScript 2018 without polyfills, checking var length/type, etc., just use the spread syntax.

function foo(var1, var2, opts){
  // set default values for parameters
  const defaultOpts = {
    a: [1,2,3],
    b: true,
    c: 0.3289,
    d: "str",
  }
  // merge default and passed-in parameters
  // defaultOpts must go first!
  const mergedOpts = {...defaultOpts, ...opts};

  // you can now refer to parameters like b as mergedOpts.b,
  // or just assign mergedOpts.b to b
  console.log(mergedOpts.a);
  console.log(mergedOpts.b);
  console.log(mergedOpts.c);  
  console.log(mergedOpts.d);
}
// the parameters you passed in override the default ones
// all JS types are supported: primitives, objects, arrays, functions, etc.
let var1, var2="random var";
foo(var1, var2, {a: [1,2], d: "differentString"});

// parameter values inside foo:
//a: [1,2]
//b: true
//c: 0.3289
//d: "differentString"

What is spread syntax?

The Rest/Spread Properties for ECMAScript proposal (stage 4) adds spread properties to object literals. It copies own enumerable properties from a provided object onto a new object. More on mdn

Note: spread syntax in object literals doesn't work in Edge and IE and it is an experimental feature. see browser compatability

AlienKevin
  • 2,691
  • 2
  • 17
  • 19
2

As this post already contains a lot of different solutions i thought i post another one.

function onlyUnique(value, index, self) {
    return self.indexOf(value) === index;
}

function overload() {
   var functions = arguments;
   var nroffunctionsarguments = [arguments.length];
    for (var i = 0; i < arguments.length; i++) {
        nroffunctionsarguments[i] = arguments[i].length;
    }
    var unique = nroffunctionsarguments.filter(onlyUnique);
    if (unique.length === arguments.length) {
        return function () {
            var indexoffunction = nroffunctionsarguments.indexOf(arguments.length);
            return functions[indexoffunction].apply(this, arguments);
        }
    }
    else throw new TypeError("There are multiple functions with the same number of parameters");

}

this can be used as shown below:

var createVector = overload(
        function (length) {
            return { x: length / 1.414, y: length / 1.414 };
        },
        function (a, b) {
            return { x: a, y: b };
        },
        function (a, b,c) {
            return { x: a, y: b, z:c};
        }
    );
console.log(createVector(3, 4));
console.log(createVector(3, 4,5));
console.log(createVector(7.07));

This solution is not perfect but i only want to demonstrate how it could be done.

remyH
  • 104
  • 8
2

You can user the 'addMethod' from John Resig. With this method you can "overload" methods based on arguments count.

// addMethod - By John Resig (MIT Licensed)
function addMethod(object, name, fn){
    var old = object[ name ];
    object[ name ] = function(){
        if ( fn.length == arguments.length )
            return fn.apply( this, arguments );
        else if ( typeof old == 'function' )
            return old.apply( this, arguments );
    };
}

I have also created an alternative to this method that uses caching to hold the variations of the function. The differencies are described here

// addMethod - By Stavros Ioannidis
function addMethod(obj, name, fn) {
  obj[name] = obj[name] || function() {
    // get the cached method with arguments.length arguments
    var method = obj[name].cache[arguments.length];

    // if method exists call it 
    if ( !! method)
      return method.apply(this, arguments);
    else throw new Error("Wrong number of arguments");
  };

  // initialize obj[name].cache
  obj[name].cache = obj[name].cache || {};

  // Check if a method with the same number of arguments exists  
  if ( !! obj[name].cache[fn.length])
    throw new Error("Cannot define multiple '" + name +
      "' methods with the same number of arguments!");

  // cache the method with fn.length arguments
  obj[name].cache[fn.length] = function() {
    return fn.apply(this, arguments);
  };
}
istavros
  • 138
  • 5
2

Function Overloading via Dynamic Polymorphism in 100 lines of JS

This is from a larger body of code which includes the isFn, isArr, etc. type checking functions. The VanillaJS version below has been reworked to remove all external dependencies, however you will have to define you're own type checking functions for use in the .add() calls.

Note: This is a self-executing function (so we can have a closure/closed scope), hence the assignment to window.overload rather than function overload() {...}.

window.overload = function () {
    "use strict"

    var a_fnOverloads = [],
        _Object_prototype_toString = Object.prototype.toString
    ;

    function isFn(f) {
        return (_Object_prototype_toString.call(f) === '[object Function]');
    } //# isFn

    function isObj(o) {
        return !!(o && o === Object(o));
    } //# isObj

    function isArr(a) {
        return (_Object_prototype_toString.call(a) === '[object Array]');
    } //# isArr

    function mkArr(a) {
        return Array.prototype.slice.call(a);
    } //# mkArr

    function fnCall(fn, vContext, vArguments) {
        //# <ES5 Support for array-like objects
        //#     See: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/apply#Browser_compatibility
        vArguments = (isArr(vArguments) ? vArguments : mkArr(vArguments));

        if (isFn(fn)) {
            return fn.apply(vContext || this, vArguments);
        }
    } //# fnCall

    //# 
    function registerAlias(fnOverload, fn, sAlias) {
        //# 
        if (sAlias && !fnOverload[sAlias]) {
            fnOverload[sAlias] = fn;
        }
    } //# registerAlias

    //# 
    function overload(vOptions) {
        var oData = (isFn(vOptions) ?
                { default: vOptions } :
                (isObj(vOptions) ?
                    vOptions :
                    {
                        default: function (/*arguments*/) {
                            throw "Overload not found for arguments: [" + mkArr(arguments) + "]";
                        }
                    }
                )
            ),
            fnOverload = function (/*arguments*/) {
                var oEntry, i, j,
                    a = arguments,
                    oArgumentTests = oData[a.length] || []
                ;

                //# Traverse the oArgumentTests for the number of passed a(rguments), defaulting the oEntry at the beginning of each loop
                for (i = 0; i < oArgumentTests.length; i++) {
                    oEntry = oArgumentTests[i];

                    //# Traverse the passed a(rguments), if a .test for the current oArgumentTests fails, reset oEntry and fall from the a(rgument)s loop
                    for (j = 0; j < a.length; j++) {
                        if (!oArgumentTests[i].tests[j](a[j])) {
                            oEntry = undefined;
                            break;
                        }
                    }

                    //# If all of the a(rgument)s passed the .tests we found our oEntry, so break from the oArgumentTests loop
                    if (oEntry) {
                        break;
                    }
                }

                //# If we found our oEntry above, .fn.call its .fn
                if (oEntry) {
                    oEntry.calls++;
                    return fnCall(oEntry.fn, this, a);
                }
                //# Else we were unable to find a matching oArgumentTests oEntry, so .fn.call our .default
                else {
                    return fnCall(oData.default, this, a);
                }
            } //# fnOverload
        ;

        //# 
        fnOverload.add = function (fn, a_vArgumentTests, sAlias) {
            var i,
                bValid = isFn(fn),
                iLen = (isArr(a_vArgumentTests) ? a_vArgumentTests.length : 0)
            ;

            //# 
            if (bValid) {
                //# Traverse the a_vArgumentTests, processinge each to ensure they are functions (or references to )
                for (i = 0; i < iLen; i++) {
                    if (!isFn(a_vArgumentTests[i])) {
                        bValid = _false;
                    }
                }
            }

            //# If the a_vArgumentTests are bValid, set the info into oData under the a_vArgumentTests's iLen
            if (bValid) {
                oData[iLen] = oData[iLen] || [];
                oData[iLen].push({
                    fn: fn,
                    tests: a_vArgumentTests,
                    calls: 0
                });

                //# 
                registerAlias(fnOverload, fn, sAlias);

                return fnOverload;
            }
            //# Else one of the passed arguments was not bValid, so throw the error
            else {
                throw "poly.overload: All tests must be functions or strings referencing `is.*`.";
            }
        }; //# overload*.add

        //# 
        fnOverload.list = function (iArgumentCount) {
            return (arguments.length > 0 ? oData[iArgumentCount] || [] : oData);
        }; //# overload*.list

        //# 
        a_fnOverloads.push(fnOverload);
        registerAlias(fnOverload, oData.default, "default");

        return fnOverload;
    } //# overload

    //# 
    overload.is = function (fnTarget) {
        return (a_fnOverloads.indexOf(fnTarget) > -1);
    } //# overload.is

    return overload;
}();

Usage:

The caller defines their overloaded functions by assigning a variable to the return of overload(). Thanks to chaining, the additional overloads can be defined in series:

var myOverloadedFn = overload(function(){ console.log("default", arguments) })
    .add(function(){ console.log("noArgs", arguments) }, [], "noArgs")
    .add(function(){ console.log("str", arguments) }, [function(s){ return typeof s === 'string' }], "str")
;

The single optional argument to overload() defines the "default" function to call if the signature cannot be identified. The arguments to .add() are:

  1. fn: function defining the overload;
  2. a_vArgumentTests: Array of functions defining the tests to run on the arguments. Each function accepts a single argument and returns truethy based on if the argument is valid;
  3. sAlias (Optional): string defining the alias to directly access the overload function (fn), e.g. myOverloadedFn.noArgs() will call that function directly, avoiding the dynamic polymorphism tests of the arguments.

This implementation actually allows for more than just traditional function overloads as the second a_vArgumentTests argument to .add() in practice defines custom types. So, you could gate arguments not only based on type, but on ranges, values or collections of values!

If you look through the 145 lines of code for overload() you'll see that each signature is categorized by the number of arguments passed to it. This is done so that we're limiting the number of tests we are running. I also keep track of a call count. With some additional code, the arrays of overloaded functions could be re-sorted so that more commonly called functions are tested first, again adding some measure of performance enhancement.

Now, there are some caveats... As Javascript is loosely typed, you will have to be careful with your vArgumentTests as an integer could be validated as a float, etc.

JSCompress.com version (1114 bytes, 744 bytes g-zipped):

window.overload=function(){'use strict';function b(n){return'[object Function]'===m.call(n)}function c(n){return!!(n&&n===Object(n))}function d(n){return'[object Array]'===m.call(n)}function e(n){return Array.prototype.slice.call(n)}function g(n,p,q){if(q=d(q)?q:e(q),b(n))return n.apply(p||this,q)}function h(n,p,q){q&&!n[q]&&(n[q]=p)}function k(n){var p=b(n)?{default:n}:c(n)?n:{default:function(){throw'Overload not found for arguments: ['+e(arguments)+']'}},q=function(){var r,s,t,u=arguments,v=p[u.length]||[];for(s=0;s<v.length;s++){for(r=v[s],t=0;t<u.length;t++)if(!v[s].tests[t](u[t])){r=void 0;break}if(r)break}return r?(r.calls++,g(r.fn,this,u)):g(p.default,this,u)};return q.add=function(r,s,t){var u,v=b(r),w=d(s)?s.length:0;if(v)for(u=0;u<w;u++)b(s[u])||(v=_false);if(v)return p[w]=p[w]||[],p[w].push({fn:r,tests:s,calls:0}),h(q,r,t),q;throw'poly.overload: All tests must be functions or strings referencing `is.*`.'},q.list=function(r){return 0<arguments.length?p[r]||[]:p},l.push(q),h(q,p.default,'default'),q}var l=[],m=Object.prototype.toString;return k.is=function(n){return-1<l.indexOf(n)},k}();
Campbeln
  • 2,880
  • 3
  • 33
  • 33
2

there is no actual overloading in JS, anyway we still can simulate method overloading in several ways:

method #1: use object

function test(x,options){
  if("a" in options)doSomething();
  else if("b" in options)doSomethingElse();
}
test("ok",{a:1});
test("ok",{b:"string"});

method #2: use rest (spread) parameters

function test(x,...p){
 if(p[2])console.log("3 params passed"); //or if(typeof p[2]=="string")
else if (p[1])console.log("2 params passed");
else console.log("1 param passed");
}

method #3: use undefined

function test(x, y, z){
 if(typeof(z)=="undefined")doSomething();
}

method #4: type checking

function test(x){
 if(typeof(x)=="string")console.log("a string passed")
 else ...
}
xx yy
  • 529
  • 1
  • 7
  • 16
2

Something like this can be done for function overloading.

function addCSS(el, prop, val) {
  return {
    2: function() {
      // when two arguments are set
      // now prop is an oject
      for (var i in prop) {
          el.style[i] = prop[i];
      }
    },
    3: function() {
      // when three arguments are set
      el.style[prop] = val;
    }
    }[arguments.length]();
}
// usage
var el = document.getElementById("demo");
addCSS(el, "color", "blue");
addCSS(el, {
    "backgroundColor": "black",
  "padding": "10px"
});

Source

Supun Kavinda
  • 1,355
  • 14
  • 13
2

Function overloading in Javascript:

Function overloading is the ability of a programming language to create multiple functions of the same name with different implementations. when an overloaded function is called it will run function a specific implementation of that function appropriate to the context of the call. This context is usually the amount of arguments is receives, and it allows one function call to behave differently depending on context.

Javascript doesn't have built-in function overloading. However, this behaviour can be emulated in many ways. Here is a convenient simple one:

function sayHi(a, b) {
  console.log('hi there ' + a);
  if (b) { console.log('and ' + b) } // if the parameter is present, execute the block
}

sayHi('Frank', 'Willem');

In scenarios where you don't know how many arguments you will be getting you can use the rest operator which is three dots .... It will convert the remainder of the arguments into an array. Beware of browser compatibilty though. Here is an example:

function foo (a, ...b) {
  console.log(b);
}

foo(1,2,3,4);
foo(1,2);
Willem van der Veen
  • 33,665
  • 16
  • 190
  • 155
2

While Default parameters is not overloading, it might solve some of the issues that developers face in this area. The input is strictly decided by the order, you can not re-order as you wish as in classical overloading:

function transformer(
    firstNumber = 1,
    secondNumber = new Date().getFullYear(),
    transform = function multiply(firstNumber, secondNumber) {
        return firstNumber * secondNumber;
    }
) {
    return transform(firstNumber, secondNumber);
}

console.info(transformer());
console.info(transformer(8));
console.info(transformer(2, 6));
console.info(transformer(undefined, 65));

function add(firstNumber, secondNumber) {
    return firstNumber + secondNumber;
}
console.info(transformer(undefined, undefined, add));
console.info(transformer(3, undefined, add));

Results in (for year 2020):

2020
16160
12
65
2021
2023

More info: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Default_parameters

basickarl
  • 37,187
  • 64
  • 214
  • 335
2

The Typescript Handbook mentions Overloads. While checking types and doing different logic based on results has been mentioned before, this approach defining multiple named functions to work with a typing system might be interesting to readers. Here is how TypeScript achieves creating a function that accepts multiple types of arguments that will direct the function logic to do different things based on incoming arguments and types:

The answer is to supply multiple function types for the same function as a list of overloads. This list is what the compiler will use to resolve function calls. Let’s create a list of overloads that describe what our pickCard accepts and what it returns.

let suits = ["hearts", "spades", "clubs", "diamonds"];

function pickCard(x: { suit: string; card: number }[]): number;
function pickCard(x: number): { suit: string; card: number };
function pickCard(x: any): any {
  // Check to see if we're working with an object/array
  // if so, they gave us the deck and we'll pick the card
  if (typeof x == "object") {
    let pickedCard = Math.floor(Math.random() * x.length);
    return pickedCard;
  }
  // Otherwise just let them pick the card
  else if (typeof x == "number") {
    let pickedSuit = Math.floor(x / 13);
    return { suit: suits[pickedSuit], card: x % 13 };
  }
}

let myDeck = [
  { suit: "diamonds", card: 2 },
  { suit: "spades", card: 10 },
  { suit: "hearts", card: 4 },
];

let pickedCard1 = myDeck[pickCard(myDeck)];
alert("card: " + pickedCard1.card + " of " + pickedCard1.suit);

let pickedCard2 = pickCard(15);
alert("card: " + pickedCard2.card + " of " + pickedCard2.suit);

With this change, the overloads now give us type checked calls to the pickCard function.

In order for the compiler to pick the correct type check, it follows a similar process to the underlying JavaScript. It looks at the overload list and, proceeding with the first overload, attempts to call the function with the provided parameters. If it finds a match, it picks this overload as the correct overload. For this reason, it’s customary to order overloads from most specific to least specific.

Note that the function pickCard(x): any piece is not part of the overload list, so it only has two overloads: one that takes an object and one that takes a number. Calling pickCard with any other parameter types would cause an error.

Danny
  • 3,982
  • 1
  • 34
  • 42
1

We made over.js to solve this problem is a very elegant way. You can do:

var obj = {

  /**
   * Says something in the console.
   *
   * say(msg) - Says something once.
   * say(msg, times) - Says something many times.
   */
  say: Over(
    function(msg$string){
      console.info(msg$string);
    },
    function(msg$string, times$number){
      for (var i = 0; i < times$number; i++) this.say(msg$string);
    }
  )

};
Mat Ryer
  • 3,797
  • 4
  • 26
  • 24
1

This is an old question but one that I think needs another entry (although I doubt anyone will read it). The use of Immediately Invoked Function Expressions (IIFE) can be used in conjunction with closures and inline functions to allow for function overloading. Consider the following (contrived) example:

var foo;

// original 'foo' definition
foo = function(a) {
  console.log("a: " + a);
}

// define 'foo' to accept two arguments
foo = (function() {
  // store a reference to the previous definition of 'foo'
  var old = foo;

  // use inline function so that you can refer to it internally
  return function newFoo(a,b) {

    // check that the arguments.length == the number of arguments 
    // defined for 'newFoo'
    if (arguments.length == newFoo.length) {
      console.log("a: " + a);
      console.log("b: " + b);

    // else if 'old' is a function, apply it to the arguments
    } else if (({}).toString.call(old) === '[object Function]') {
      old.apply(null, arguments);
    }
  }
})();

foo(1);
> a: 1
foo(1,2);
> a: 1
> b: 2
foo(1,2,3)
> a: 1

In short, the use of the IIFE creates a local scope, allowing us to define the private variable old to store a reference to the initial definition of the function foo. This function then returns an inline function newFoo that logs the contents of both two arguments if it is passed exactly two arguments a and b or calls the old function if arguments.length !== 2. This pattern can be repeated any number of times to endow one variable with several different functional defitions.

wvandaal
  • 4,265
  • 2
  • 16
  • 27
1

I would like to share a useful example of overloaded-like approach.

function Clear(control)
{
  var o = typeof control !== "undefined" ? control : document.body;
  var children = o.childNodes;
  while (o.childNodes.length > 0)
    o.removeChild(o.firstChild);
}

Usage: Clear(); // Clears all the document

Clear(myDiv); // Clears panel referenced by myDiv

1

JavaScript is untyped language, and I only think that makes sense to overload a method/function with regards to the number of params. Hence, I would recommend to check if the parameter has been defined:

myFunction = function(a, b, c) {
     if (b === undefined && c === undefined ){
          // do x...
     }
     else {
          // do y...
     }
};
Antonio
  • 851
  • 2
  • 8
  • 17
1

As of July 2017, the following has been the common technique. Note that we can also perform type checking within the function.

function f(...rest){   // rest is an array
   console.log(rest.length);
   for (v of rest) if (typeof(v)=="number")console.log(v);
}
f(1,2,3);  // 3 1 2 3
Chong Lip Phang
  • 8,755
  • 5
  • 65
  • 100
1

For your use case, this is how I would tackle it with ES6 (since it's already the end of 2017):

const foo = (x, y, z) => {
  if (y && z) {
    // Do your foo(x, y, z); functionality
    return output;
  }
  // Do your foo(x); functionality
  return output;
}

You can obviously adapt this to work with any amount of parameters and just change your conditional statements accordingly.

Barry Michael Doyle
  • 9,333
  • 30
  • 83
  • 143
0

The first option really deserves attention cause it's the thing I've come up in quite complex code setup. So, my answer is

  1. Using different names in the first place

With a little but essential hint, names should look different for computer, but not for you. Name overloaded functions like: func, func1, func2.

alehro
  • 2,198
  • 2
  • 25
  • 41
  • I was going to try overloading but decided to just use different names, e.g. getDeviceInfoByID and getDeviceInfoByType... – CramerTV Oct 21 '14 at 22:48
0

So I really liked this way of doing things that I found in secrets of the javascript ninja

function addMethod(object,name,fn){
  var old = object[name];
  object[name] = function(){
    if (fn.length == arguments.length){
      return fn.apply(this,arguments);
    } else if(typeof old == 'function'){
        return old.apply(this,arguments);
    }
  }
}

you then use addMethod to add overloaded functions to any object. The main confusion in this code for me was the use of fn.length == arguments.length -- this works because fn.length is the number of expected parameters, while arguments.length is the number of parameters that are actually called with the function. The reason the anonymous function has no argument is because you can pass in any number of arguments in javascript and the language is forgiving.

I liked this because you can use it everywhere - just create this function and simply use the method in whatever code base you want.

It also avoids having a ridiculously large if/switch statement, which becomes hard to read if you start writing complex code (the accepted answer will result in this).

In terms of cons, I guess the code is initially a little obscure...but I'm not sure of others?

praks5432
  • 7,246
  • 32
  • 91
  • 156
0

I like @AntouanK's approach. I often find myself offering a function with different numbers o parameters and different types. Sometimes they don't follow a order. I use to map looking the types of parameters:

findUDPServers: function(socketProperties, success, error) {
    var fqnMap = [];

    fqnMap['undefined'] = fqnMap['function'] = function(success, error) {
        var socketProperties = {name:'HELLO_SERVER'};

        this.searchServers(socketProperties, success, error);
    };

    fqnMap['object'] = function(socketProperties, success, error) {
        var _socketProperties = _.merge({name:'HELLO_SERVER'}, socketProperties || {});

        this.searchServers(_socketProperties, success, error);
    };

    fqnMap[typeof arguments[0]].apply(this, arguments);
}
Andre Medeiros
  • 224
  • 2
  • 6
0

I've been using this function to prettify my overloads for years:

function overload(){
  const fs = arguments, fallback = fs[fs.length - 1];
  return function(){
    const f = fs[arguments.length] || (arguments.length >= fs.length ? fallback : null);
    return f.apply(this, arguments);
  }
}

Demostrated:

function curry1(f){
  return curry2(f, f.length);
}

function curry2(f, minimum){
  return function(...applied){
    if (applied.length >= minimum) {
      return f.apply(this, applied);
    } else {
      return curry2(function(...args){
        return f.apply(this, applied.concat(args));
      }, minimum - applied.length);
    }
  }
}

export const curry = overload(null, curry1, curry2);

Take a look at jQuery's off method:

  function off( types, selector, fn ) {
    var handleObj, type;
    if ( types && types.preventDefault && types.handleObj ) {

        // ( event )  dispatched jQuery.Event
        handleObj = types.handleObj;
        jQuery( types.delegateTarget ).off(
            handleObj.namespace ?
                handleObj.origType + "." + handleObj.namespace :
                handleObj.origType,
            handleObj.selector,
            handleObj.handler
        );
        return this;
    }
    if ( typeof types === "object" ) {

        // ( types-object [, selector] )
        for ( type in types ) {
            this.off( type, selector, types[ type ] );
        }
        return this;
    }
    if ( selector === false || typeof selector === "function" ) {

        // ( types [, fn] )
        fn = selector;
        selector = undefined;
    }
    if ( fn === false ) {
        fn = returnFalse;
    }
    return this.each( function() {
        jQuery.event.remove( this, types, fn, selector );
    } );
  }

Many overloaded functions when optimized for performance are nigh unreadable. You have to decipher the head of the function. This is perhaps faster than using an overload function like I provide; however, it is slower from a human perspective with regard to identifying which overload was called.

Mario
  • 6,572
  • 3
  • 42
  • 74
-1

I am working on a library that provides class like code capabilities to Javascript, currently it supports constructors, inheritance, methods overload by number of params and by types of params, mixins, statics properties and singleton.

See an example of method overloading using that library:

eutsiv.define('My.Class', {
    constructor: function() {
        this.y = 2;
    },
    x: 3,
    sum: function() {
        return this.x + this.y;
    },
    overloads: {
        value: [
            function() { return this.x + ', ' + this.y },
            function(p1) { this.x = p1; },
            function(p1, p2) { this.x = p1; this.y = p2; }  // will set x and y
        ]
    }
});

var test = new My.Class({ x: 5 });   // create the object
test.value();                        // will return '5, 2'
test.sum();                          // will return 7
test.value(13);                      // will set x to 13
test.value();                        // will return '13, 2'
test.sum();                          // will return 15
test.value(10, 20);                  // will set x to 10 and y to 20
test.value();                        // will return '10, 20'
test.sum();                          // will return 30

Any feedback, bug fixes, docs and tests improves are welcome!

https://github.com/eutsiv/eutsiv.js