Sovraccarico delle funzioni in Javascript – Best practice

Qual è il modo migliore per sovraccaricare le funzioni in Javascript?

So che non è ansible sovraccaricare le funzioni in Javascript come in altre lingue. Se avessi bisogno di una funzione con due usi foo(x) e foo(x,y,z) che è il modo migliore / preferito:

  1. Usando nomi diversi in primo luogo
  2. Usando argomenti opzionali come y = y || 'default' y = y || 'default'
  3. Usando il numero di argomenti
  4. Verifica dei tipi di argomenti
  5. O come?

Il modo migliore per eseguire l’overloading delle funzioni con i parametri non è controllare la lunghezza dell’argomento oi tipi; controllare i tipi renderà il tuo codice lento e ti divertirai con matrici, null, oggetti, ecc.

Ciò che la maggior parte degli sviluppatori fa è virare su un object come ultimo argomento ai loro metodi. Questo object può contenere qualsiasi cosa.

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

Quindi puoi gestirlo in ogni caso nel tuo metodo. [Switch, if-else, ecc.]

Faccio spesso questo:

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 

Equivalente JavaScript:

 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 

Questo particolare esempio è in realtà più elegante in javascript di C #. I parametri che non sono specificati sono ‘indefiniti’ in javascript, che restituisce false in un’istruzione if. Tuttavia, la definizione della funzione non trasmette l’informazione che p2 e p3 sono opzionali. Se è necessario un sovraccarico eccessivo, jQuery ha deciso di utilizzare un object come parametro, ad esempio jQuery.ajax (opzioni). Sono d’accordo con loro sul fatto che questo è l’approccio più potente e chiaramente documentabile all’overloading, ma raramente ho bisogno di più di uno o due parametri opzionali rapidi.

EDIT: modificato IF test per suggerimento di Ian

Non esiste un vero sovraccarico di funzioni in JavaScript poiché consente di passare qualsiasi numero di parametri di qualsiasi tipo. Devi controllare all’interno della funzione quanti argomenti sono stati passati e che tipo sono.

La risposta corretta è NON C’È SOVRACCARICO IN JAVASCRIPT.

Il controllo / il passaggio all’interno della funzione non è SOVRACCARICO.

Il concetto di sovraccarico: in alcuni linguaggi di programmazione, l’overloading delle funzioni o l’overloading dei metodi è la possibilità di creare più metodi con lo stesso nome con diverse implementazioni. Le chiamate a una funzione sovraccaricata eseguiranno un’implementazione specifica di tale funzione appropriata al contesto della chiamata, consentendo a una chiamata di funzione di eseguire attività diverse a seconda del contesto.

Ad esempio, doTask () e doTask (object O) sono metodi sovraccaricati. Per chiamare quest’ultimo, un object deve essere passato come parametro, mentre il primo non richiede un parametro e viene chiamato con un campo parametro vuoto. Un errore comune sarebbe assegnare un valore predefinito all’object nel secondo metodo, il che comporterebbe un errore di chiamata ambiguo, in quanto il compilatore non saprebbe quale dei due metodi utilizzare.

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

Tutte le implementazioni suggerite sono grandiose, ma la verità è che non esiste un’implementazione nativa per JavaScript.

Ci sono due modi in cui potresti affrontare questo meglio:

  1. Passa un dizionario (array associativo) se vuoi lasciare molta flessibilità

  2. Prendi un object come argomento e usa l’ereditarietà basata sul prototipo per aggiungere flessibilità.

Ecco un test di benchmark sull’overloading delle funzioni: http://goo.gl/UyYAD (codice mostrato in questo post). Mostra che l’overloading delle funzioni (tenendo conto dei tipi) può essere circa 13 volte più lento nel V8 di Google Chrome a partire dal 16.0 (beta) .

Oltre a passare un object (es. {x: 0, y: 0} ), si può anche prendere l’approccio C quando appropriato, nominando i metodi di conseguenza. Ad esempio, Vector.AddVector (vector), Vector.AddIntegers (x, y, z, …) e Vector.AddArray (integerArray). Puoi guardare le librerie C, come OpenGL, per dare un nome all’ispirazione.

Modifica : ho aggiunto un benchmark per passare un object e testare l’object usando sia 'param' in arg e arg.hasOwnProperty('param') , e l’overloading della funzione è molto più veloce del passaggio di un object e del controllo delle proprietà (in questo benchmark almeno).

Dal punto di vista del design, l’overloading delle funzioni è valido o logico solo se i parametri sovraccaricati corrispondono alla stessa azione. Quindi è ovvio che dovrebbe esserci un metodo sottostante che riguarda solo dettagli specifici, altrimenti potrebbe indicare scelte progettuali inappropriate. Quindi si potrebbe anche risolvere l’uso dell’overloading della funzione convertendo i dati in un object rispettivo. Ovviamente si deve considerare l’ambito del problema in quanto non è necessario fare progetti elaborati se si intende semplicemente stampare un nome, ma per la progettazione di quadri e librerie tale pensiero è giustificato.

Il mio esempio deriva da un’implementazione Rectangle – da qui la citazione di Dimension and Point. Forse Rectangle potrebbe aggiungere un metodo GetRectangle() al prototipo Dimension and Point , quindi il problema di overloading delle funzioni viene ordinato. E i primitivi? Bene, abbiamo la lunghezza dell’argomento, che ora è un test valido poiché gli oggetti hanno un metodo GetRectangle() .

 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); 

Il modo migliore dipende in realtà dalla funzione e dagli argomenti. Ciascuna delle tue opzioni è una buona idea in diverse situazioni. In genere li provo nel seguente ordine finché uno di loro non funziona:

  1. Usando argomenti opzionali come y = y || ‘predefinito’. Questo è utile se riesci a farlo, ma potrebbe non funzionare sempre praticamente, ad esempio quando 0 / null / indefinito sarebbe un argomento valido.

  2. Usando il numero di argomenti. Simile all’ultima opzione, ma potrebbe funzionare quando # 1 non funziona.

  3. Verifica dei tipi di argomenti. Questo può funzionare in alcuni casi in cui il numero di argomenti è lo stesso. Se non è ansible determinare in modo affidabile i tipi, potrebbe essere necessario utilizzare nomi diversi.

  4. Usando nomi diversi in primo luogo. Potrebbe essere necessario farlo se le altre opzioni non funzionano, non sono pratiche o per coerenza con altre funzioni correlate.

Se avessi bisogno di una funzione con due usi foo (x) e foo (x, y, z) quale è il modo migliore / preferito?

Il problema è che JavaScript NON supporta in modo nativo l’overloading dei metodi. Quindi, se vede / analizza due o più funzioni con lo stesso nome, prenderà in considerazione solo l’ultima funzione definita e sovrascriverà quelle precedenti.

Uno dei modi in cui penso sia adatto per la maggior parte del caso è il seguente:

Diciamo che hai un metodo

 function foo(x) { } 

Invece di un metodo di overload che non è ansible in javascript , puoi definire un nuovo metodo

 fooNew(x,y,z) { } 

e quindi modificare la 1a funzione come segue:

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

Se si dispone di molti di questi metodi sovraccarichi, si consideri l’utilizzo di switch piuttosto che istruzioni if-else .

( maggiori dettagli )

Non sono sicuro delle migliori pratiche, ma ecco come lo faccio:

 /* * 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" 

Ho appena provato questo, forse è adatto alle tue esigenze. A seconda del numero degli argomenti, è ansible accedere a una funzione diversa. La inizializzi la prima volta che la chiami. E la mappa delle funzioni è nascosta nella chiusura.

 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; }; 

Provalo.

 TEST.multiFn("0") .multiFn() .multiFn("0","1","2"); 

Poiché JavaScript non ha opzioni di sovraccarico di funzione, è ansible utilizzare invece l’object. Se ci sono uno o due argomenti richiesti, è meglio tenerli separati dall’object opzioni. Ecco un esempio su come utilizzare le opzioni object e valori popolati sul valore predefinito nel caso in cui il valore non fosse passato nell’object opzioni.

  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 + "}"; } 

ecco un esempio su come usare l’object options

Non c’è modo di funzionare con overloading in javascript. Quindi, mi raccomando il seguente metodo di typeof() invece di funzioni multiple per il sovraccarico fasullo.

 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!!"); } } 

In bocca al lupo!

controllalo. È molto bello http://ejohn.org/blog/javascript-method-overloading/ Trucco Javascript per permetterti di fare chiamate come questa:

 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 

INTRODUZIONE

Finora la lettura di tante risposte avrebbe dato a qualcuno un mal di testa. Chiunque cerchi di conoscere il concetto dovrebbe conoscere i seguenti prerequisiti .

Function overloading Definition , Function Length property , Function argument property

Function overloading nella sua forma più semplice significa che una funzione esegue compiti diversi sulla base del numero di argomenti che gli vengono passati. In particolare TASK1, TASK2 e TASK3 sono evidenziati di seguito e vengono eseguiti sulla base del numero di arguments passati alla stessa funzione 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 

NOTA : JS non fornisce capacità intrinseche di sovraccarico delle funzioni.

Alternativa

John E Resig (creatore di JS) ha indicato un’alternativa che utilizza i prerequisiti sopra riportati per ottenere la capacità di implementare l’overloading delle funzioni.

Il codice seguente utilizza un approccio semplice ma ingenuo usando l’istruzione if-else o switch .

  • valuta la proprietà argument-length .
  • valori diversi comportano l’invocazione di diverse funzioni.
 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 ... } } } 

Poiché questo post contiene già molte soluzioni diverse, ho pensato di postarne un altro.

 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"); } 

questo può essere usato come mostrato di seguito:

 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)); 

Questa soluzione non è perfetta ma voglio solo dimostrare come potrebbe essere fatto.

È ansible utilizzare ‘addMethod’ da John Resig. Con questo metodo è ansible “sovraccaricare” i metodi basati sul conteggio degli argomenti.

 // 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 ); }; } 

Ho anche creato un’alternativa a questo metodo che utilizza la memorizzazione nella cache per contenere le variazioni della funzione. Le differenze sono descritte qui

 // 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); }; } 

Forwarding Pattern => la migliore pratica sull’overloading JS

Inoltra a un’altra funzione il cui nome viene creato dal 3 ° e 4 ° punto:

  1. Usando il numero di argomenti
  2. Verifica dei tipi di argomenti
 window['foo_'+arguments.length+'_'+Array.from(arguments).map((arg)=>typeof arg).join('_')](...arguments) 

Applicazione sul tuo caso:

  function foo(){ return window['foo_'+arguments.length+Array.from(arguments).map((arg)=>typeof arg).join('_')](...arguments); } //------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(){ } 

Altro campione complesso:

  function foo(){ return window['foo_'+arguments.length+Array.from(arguments).map((arg)=>typeof arg).join('_')](...arguments); } /** 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 .... 

Un altro modo per avvicinarsi a questo è usando la variabile speciale: argomenti , questa è un’implementazione:

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

quindi puoi modificare questo codice in:

 function sum(){ var s = 0; if (typeof arguments[0] !== "undefined") s += arguments[0]; . . . return s; } 

La prima opzione merita davvero attenzione perché è la cosa che mi è venuta in un setup di codice piuttosto complesso. Quindi, la mia risposta è

  1. Usando nomi diversi in primo luogo

Con un suggerimento piccolo ma essenziale, i nomi dovrebbero apparire diversi per il computer, ma non per te. Nome funzioni sovraccaricate come: func, func1, func2.

Questa è una vecchia domanda, ma credo che abbia bisogno di un’altra voce (anche se dubito che qualcuno lo leggerà). L’uso delle espressioni di funzione immediatamente invocate (IIFE) può essere utilizzato insieme alle chiusure e alle funzioni in linea per consentire il sovraccarico della funzione. Considera il seguente esempio (forzato):

 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 breve, l’uso dell’IIFE crea uno scope locale, permettendoci di definire la variabile privata old per memorizzare un riferimento alla definizione iniziale della funzione foo . Questa funzione restituisce quindi una funzione inline newFoo che registra il contenuto di entrambi i due argomenti se viene passato esattamente due argomenti b o chiama la old funzione if arguments.length !== 2 . Questo schema può essere ripetuto un numero qualsiasi di volte per dotare una variabile di diverse difese funzionali diverse.

JavaScript è un linguaggio non tipizzato, e penso solo che abbia senso sovraccaricare un metodo / funzione per quanto riguarda il numero di parametri. Quindi, consiglierei di verificare se il parametro è stato definito:

 myFunction = function(a, b, c) { if (b === undefined && c === undefined ){ // do x... } else { // do y... } }; 

A partire da luglio 2017, la seguente è stata la tecnica comune. Si noti che è anche ansible eseguire il controllo dei tipi all’interno della funzione.

 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 

Per il tuo caso d’uso, è così che vorrei affrontarlo con ES6 (dato che è già la fine del 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; } 

Ovviamente puoi adattarlo a lavorare con qualsiasi quantità di parametri e modificare semplicemente le tue dichiarazioni condizionali di conseguenza.

Funzione di sovraccarico tramite polimorfismo dinamico in 100 linee di JS

  • VanillaJS, nessuna dipendenza esterna
  • Supporto completo del browser: Array.prototype.slice , Object.prototype.toString
  • 1114 byte uglify’d / 744 byte g-zippati

Questo proviene da un corpo di codice più grande che include le funzioni di controllo del tipo isFn , isArr , ecc. La versione di VanillaJS di seguito è stata rielaborata per rimuovere tutte le dipendenze esterne, tuttavia è necessario definire le proprie funzioni di controllo dei tipi da utilizzare nelle chiamate .add() .

Nota: questa è una funzione autoeseguibile (quindi possiamo avere un ambito di chiusura / chiusura), quindi l’assegnazione a window.overload piuttosto che 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) { //#  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; }(); 

Uso:

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 function s defining the tests to run on the arguments . Each function accepts a single argument and returns true thy based on if the argument is valid;
  3. sAlias (Optional): string defining the alias to directly access the overload function ( fn ), eg 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 

We made over.js to solve this problem is a very elegant way. Tu puoi fare:

 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); } ) }; 

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?

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

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); } 

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.

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