Frage

Was ist der beste Weg(s) auf gefälschte überladen von Funktionen in Javascript?

Ich weiß, es ist nicht möglich, zu überladen mit Funktionen, die in Javascript-wie in anderen Sprachen.Wenn ich brauchte eine Funktion mit zwei verwendet foo(x) und foo(x,y,z) was ist der beste / bevorzugte Weg:

  1. Unter verschiedenen Namen in den ersten Platz
  2. Mithilfe von optionalen Argumenten wie y = y || 'default'
  3. Mit der Anzahl der Argumente
  4. Überprüfung der Typen der Argumente
  5. Oder wie?
War es hilfreich?

Lösung

Der beste Weg, Funktion zu tun mit den Parametern Überlastung ist nicht das Argument Länge oder die Typen zu überprüfen; die Typen Überprüfung wird nur der Code langsam machen und Sie haben den Spaß von Arrays, nulls, Objekte, etc.

Was die meisten Entwickler tun ist, tack auf einem Objekt als letztes Argument zu ihren Methoden. Diese Aufgabe kann alles halten.

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

Dann können Sie damit umgehen irgendwie, das Sie in Ihrer Methode wollen. [Switch, if-else, etc.]

Andere Tipps

ich oft tun:

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-äquivalent:

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

Dieses spezielle Beispiel ist eigentlich mehr elegant in Javascript als C #. Parameter, die nicht angegeben sind, werden ‚undefined‘ in Javascript, die in einer if-Anweisung falsch ergibt. Allerdings ist die Funktionsdefinition vermittelt nicht die Informationen, die P2 und P3 sind optional. Wenn Sie eine Menge von Überlastung benötigen, hat jQuery beschlossen, ein Objekt als Parameter zu verwenden, zum Beispiel jQuery.ajax (Optionen). Ich bin damit einverstanden, sie mit, dass dies der stärkste und eindeutig dokumentierbar Ansatz zu einer Überlastung, aber ich brauche nur selten mehr als ein oder zwei schnelle optionale Parameter.

EDIT: geändert IF-Test pro Ians Vorschlag

Es gibt keine wirkliche Funktion in JavaScript Überlastung, da es eine beliebige Anzahl von Parametern eines beliebigen Typs passieren läßt. Sie haben innerhalb der Funktion, wie viele Argumente überprüfen weitergeleitet wurden, und was Typ sie sind.

Die richtige Antwort ist, gibt es keine Überlastung in JavaScript.

Überprüfen / Wechsel in der Funktion ist nicht zu überlasten.

Das Konzept der Überlastung: In einigen Programmiersprachen, Überladen von Funktionen oder Verfahren Überlastung ist die Fähigkeit, mehrere Methoden mit dem gleichen Namen mit unterschiedlichen Implementierungen zu erstellen. Anrufe an eine überladene Funktion wird eine spezifische Implementierung dieser Funktion der jeweiligen Situation angemessen des Anrufs ausgeführt, so dass ein Funktionsaufruf an unterschiedliche Aufgaben je nach Kontext.

Beispiel doTask () und doTask (Objekt O) sind Methoden überlastet. Um letzteres zu nennen, muss ein Objekt als Parameter übergeben werden, während die erstere keinen Parameter erfordert, und wird mit einem leeren Parameterfeld genannt. Ein häufiger Fehler wäre, einen Standardwert für das Objekt in dem zweiten Verfahren zuordnen, die in einem zweideutigen Anruffehler führen würden, da der Compiler nicht, welche der beiden Methoden kennen würde zu verwenden.

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

Alle vorgeschlagenen Implementierungen sind groß, aber die Wahrheit gesagt werden, gibt es keine native Implementierung für JavaScript.

Es gibt zwei Möglichkeiten, wie Sie könnten nähern dies besser:

  1. Führen Sie ein Wörterbuch (assoziatives Array), wenn Sie ein hohes Maß an Flexibilität

  2. verlassen wollen
  3. ein Objekt als Argument nehmen und Prototyp basierte Vererbung Flexibilität hinzuzufügen.

Hier ist ein Ansatz, der reale Methode ermöglicht Parametertypen Überlastung verwendet wird, wie folgt dar:

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

Edit (2018) . Da dies im Jahr 2011 geschrieben wurde, hat sich die Geschwindigkeit der direkten Methode Anrufe stark erhöht, während die Geschwindigkeit der überladenen Methoden haben nicht

Es ist kein Ansatz, den ich empfehlen würde, aber es ist eine lohnendes Denken Übung, darüber nachzudenken, wie man diese Art von Problemen zu lösen.


Hier ist ein Maßstab für die verschiedenen Ansätze - https://jsperf.com/function-overloading. Es zeigt, dass die Funktion Überlastung (Typen berücksichtigt) um seine 13-mal langsamer in Google Chrome V8 von 16,0 (beta) .

Neben ein Objekt Passing (d.h. {x: 0, y: 0}), kann man auch den C-Ansatz gegebenenfalls die Methoden entsprechend zu benennen. Zum Beispiel Vector.AddVector (Vektor), Vector.AddIntegers (x, y, z, ...) und Vector.AddArray (Integer). Sie können für die Benennung von Inspiration bei C-Bibliotheken, wie OpenGL aussehen.

Bearbeiten : Ich habe einen Maßstab für das Bestehen eines Objekts und Prüfung für das Objekt unter Verwendung von sowohl 'param' in arg und arg.hasOwnProperty('param') hinzugefügt und Funktion Überlastung ist viel schneller als ein Objekt vorbei und Objekte (in dieser Prüfung Benchmark zumindest).

Aus gestalterischen Sicht ist Funktion Überlastung nur gültig oder logisch, wenn die überladenen Parameter auf die gleiche Aktion entsprechen. So liegt es nahe, dass es sollte eine zugrunde liegende Methode sein, die nur mit speziellen Details, ansonsten, dass ein unangemessenen Design-Entscheidungen hinweisen. So könnte man auch die Verwendung von Funktions Überlastung beheben, indem Daten mit einem entsprechenden Objekt zu konvertieren. Natürlich muss man den Umfang des Problems betrachten, da es bei der Herstellung von aufwendigen Design keine Notwendigkeit, wenn Ihre Absicht, nur einen Namen drucken ist, aber für die Gestaltung von Rahmenbedingungen und Bibliotheken solche Gedanken gerechtfertigt ist.

Mein Beispiel stammt aus einem Rechteck Implementierung - also die Erwähnung von Dimension und Point. Vielleicht ein GetRectangle() Verfahren zum Dimension und Point Prototyp, und dann die Funktion Ausgabe Überlastung wird sortiert Rechteck könnte hinzufügen. Und was ist Primitiven? Nun, wir haben Argument Länge, die nun ein gültiger Test ist da Objekte eine GetRectangle() Methode haben.

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

Der beste Weg, hängt wirklich von der Funktion und den Argumenten. Jede der Optionen ist eine gute Idee, in verschiedenen Situationen. Ich versuche, diese in der Regel in der folgenden Reihenfolge, bis einer von ihnen arbeitet:

  1. Mit optionalen Argumenten wie y = y || ‚Default‘. Das ist praktisch, wenn Sie es tun können, aber es kann nicht immer praktisch arbeiten, z.B. wenn 0 / null / undefiniert wäre ein gültiges Argument sein.

  2. Verwenden Anzahl von Argumenten. ähnlich wie bei der letzten Option kann aber funktionieren, wenn # 1 nicht funktioniert.

  3. Überprüfen Arten von Argumenten. Dies kann in einigen Fällen arbeiten, in denen die Anzahl der Argumente sind das gleiche. Wenn Sie die Typen nicht zuverlässig bestimmen können, müssen Sie möglicherweise unterschiedliche Namen verwenden.

  4. Mit verschiedenen Namen an erster Stelle. Sie können dies, wenn die anderen Optionen funktionieren nicht tun müssen, nicht praktikabel ist, oder für die Übereinstimmung mit anderen verwandten Funktionen.

  

Wenn ich eine Funktion mit zwei benötigt verwendet foo (x) und foo (x, y, z), welche die beste / bevorzugte Weg ist?

Das Problem ist, dass JavaScript nativ NICHT Methode Überlastung unterstützen. Also, wenn es sieht, / parst zwei oder mehr Funktionen mit gleichen Namen wird es nur die letzte definierte Funktion prüfen und die vorhergehenden überschreibt.

Eine der Art und Weise denke ich, für die meisten der Fall geeignet ist, ist folgt -

Lassen Sie uns sagen Sie Methode haben

function foo(x)
{
} 

Statt Methode Überlastung , die nicht möglich in Javascript ist Sie können eine neue Methode definieren

fooNew(x,y,z)
{
}

und ändern Sie dann die erste Funktion wie folgt -

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

Wenn Sie viele solche ladenen Methoden switch Erwägen Sie die Verwendung als nur if-else Aussagen.

( mehr Details )

PS: über Link geht zu meinem persönlichen Blog, dass zusätzliche Details hat

.

Ich bin mir nicht sicher über Best Practice, aber hier ist, wie ich es tun:

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

Ich habe gerade versucht dies, vielleicht ist es Ihren Bedürfnissen entspricht. Je nach Anzahl der Argumente, können Sie eine andere Funktion zugreifen. Sie initialisieren es das erste Mal, wenn Sie es nennen. Und die Funktion Karte in der Schließung versteckt.

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

Testen Sie es.

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

Da JavaScript nicht über Funktion Überlastung Optionen Objekt kann stattdessen verwendet werden. Wenn es ein oder zwei erforderliche Argumente sind, ist es besser, sie trennen zu verhindern, die Optionen Objekt. Hier ist ein Beispiel dafür, wie Optionen verwenden Objekt behandelt und Wert Wert, falls der Standard, wenn der Wert nicht in den Optionen übergeben wurde widersprechen.

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

}

hier ist ein Beispiel dafür, wie Optionen verwenden Objekt

Es gibt keine Möglichkeit in Javascript-Funktion zu überlasten. So empfehle ich wie die folgenden von typeof() Verfahren statt Mehrfachfunktion zu fälschen Überlastung.

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

Viel Glück!

EINFÜHRUNG

Bisher durch so viele Antworten liest jemand würde Kopfschmerzen. Jeder, der versucht, das Konzept wissen müßte das folgende Voraussetzung s kennen.

Function overloading Definition , Function Length property , Function argument property

Function overloading in seiner einfachsten Form bedeutet, dass eine Funktion verschiedene Aufgaben auf der Grundlage der Anzahl der Argumente durchführt, die an sie übergeben werden. Insbesondere die TASK1, TASK2 und TASK3 sind unten hervorgehoben und auf der Grundlage der Anzahl von arguments geleitet werden, um die gleiche Funktion fooYo durchgeführt werden.

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

Hinweis - JS bietet keine eingebaute Fähigkeit der Funktion Überlastung.

Alternative

John E Resig (Konzept von JS) hat eine Alternative hingewiesen, die die obigen Voraussetzungen nutzt die Fähigkeit zu erreichen, um eine Überlastung Funktion zu implementieren.

Der folgende Code verwendet einen einfachen, aber naiven Ansatz von if-else oder switch Anweisung.

  • wertet die argument-length Eigenschaft.
  • ergeben sich unterschiedliche Werte in Aufruf verschiedener Funktionen.

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

Eine andere Technik ist viel sauberer und dynamisch. Der Höhepunkt dieser Technik ist die addMethod generische Funktion.

  • wir eine Funktion addMethod definieren, die unterschiedlichen Funktionen zu einem Objekt mit den gleichen Namen hinzufügen verwendet wird, aber verschiedene Funktionalitäten .

  • unterhalb der addMethod Funktion akzeptiert drei params Name object, Funktionsnamen name und die Funktion Objekt, das wir aufgerufen werden fn wollen.

  • Innerhalb addMethod Definition var old speichert die Bezugnahme auf die vorherige function mit Hilfe von Verschluss gespeichert werden -. Eine Schutzblase

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

  • Verwendung Debugger den Code Fluss zu verstehen.
  • unterhalb dem addMethod fügt drei Funktionen, die bei der Verwendung von ninja.whatever(x) mit der Anzahl von Argumenten x aufgerufen, die alles sein kann, das heißt entweder leer ist oder eine oder mehrere rufen verschiedene Funktionen, wie definiert, während der Verwendung der addMethod Funktion zu machen.

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

Eine andere Möglichkeit, diesen Ansatz ist durch die besondere Variable: Argumente , das ist eine Implementierung:

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

, so dass Sie diesen Code ändern können:

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

check this out. Es ist sehr cool. http://ejohn.org/blog/javascript-method-overloading/ Trick Javascript, damit Sie Anrufe wie dies zu tun:

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

Wie dieser Beitrag bereits viele verschiedene Lösungen enthält ich dachte, ich einen anderen Posten.

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

}

Dies kann verwendet werden, wie unten dargestellt:

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

Diese Lösung ist nicht perfekt, aber ich will nur zeigen, wie es getan werden könnte.

Sie können Benutzer die 'addMethod' von John Resig. Mit dieser Methode können Sie auf „Überlast“ Methoden, die auf Argumente zählen.

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

Ich habe erstellt auch eine Alternative zu diesem Verfahren, das Caching, die Variationen der Funktion zu halten verwendet. Die differencies werden hier beschrieben

// 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 => die beste Praxis auf JS Überlastung

Weiterleiten an eine andere Funktion, die Namen von den 3. und 4. Punkten aufgebaut ist:

  
      
  1. Verwenden Anzahl von Argumenten
  2.   
  3. Überprüfen Arten von Argumenten
  4.   
window['foo_'+arguments.length+'_'+Array.from(arguments).map((arg)=>typeof arg).join('_')](...arguments)

Anwendung auf Ihrem Fall:

 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(){

  }

Andere Komplexe Beispiel:

      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 ....   

Das Überladen von Funktionen über die Dynamischen Polymorphismus in 100 Zeilen JS

Dies ist von einem größeren Körper von code umfasst die isFn, isArr, etc.Typprüfung Funktionen.Die VanillaJS version unten wurde überarbeitet und entfernen Sie alle externen Abhängigkeiten, aber Sie müssen definieren Sie eigene Typprüfung Funktionen für die Verwendung in der .add() Anrufe.

Hinweis: Dies ist eine selbstausführende Funktion (so können wir eine Schließung/Umfang geschlossen), damit die Zuordnung zu window.overload anstatt 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;
}();

Verwendung:

Der Anrufer legt Ihre überladene Funktionen durch Zuweisung einer variable für die Rückgabe des overload().Dank der Verkettung der zusätzlichen überlastungen können definiert werden in Serie:

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

Die einzigen optionalen argument overload() definiert die "default" - Funktion zu nennen, wenn die Signatur nicht identifiziert werden können.Die Argumente .add() sind:

  1. fn: function Definition der überlastung;
  2. a_vArgumentTests: Array von functions definieren Sie die tests, die mit dem arguments.Jeder function akzeptiert ein einzelnes argument und gibt truedein basiert auf, wenn das argument gültig ist;
  3. sAlias (Optional): string definieren Sie den alias direkt auf die überlast-Funktion (fn), z.B. myOverloadedFn.noArgs() nenne diese Funktion direkt, vermeiden Sie den dynamischen Polymorphismus tests der Argumente.

Diese Implementierung tatsächlich erlaubt für mehr als nur die traditionelle Funktion überlastungen, wie die zweite a_vArgumentTests argument .add() in der Praxis definiert benutzerdefinierte Typen.So, Sie könnte gate Argumente nicht nur nach Typ, sondern auf Bereiche, Werte oder Gruppen von Werten!

Wenn dich mal durch die 145 Zeilen code für overload() Sie werden sehen, dass jede Signatur ist kategorisiert nach der Anzahl der arguments übergeben.Dies ist so, dass wir eine Begrenzung der Anzahl der tests, die wir ausgeführt werden.Ich habe auch verfolgen einen Anruf zählen.Mit einigen zusätzlichen code werden die arrays, die von überladenen Funktionen könnten wieder so sortiert, dass Sie häufiger Funktionen aufgerufen werden zuerst getestet, wieder hinzufügen, ein Maß für die Leistungssteigerung.

Nun, es gibt einige Einschränkungen...Javascript ist lose typisiert, Sie müssen vorsichtig sein mit Ihre vArgumentTests als integer konnte validiert werden, als float, etc.

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

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

Sie können jetzt Funktion in ECMAScript 2018 ohne polyfills Überlastung, var Länge / Typ Überprüfung usw. nur verwenden, um die 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"

Was ist verbreitet Syntax?

  

Der Rest / Spread Eigenschaften für ECMAScript Vorschlag (Stufe 4) Addiert Eigenschaften verteilt Literale zu widersprechen. Es Kopien besitzen enumerable Eigenschaften aus einem bereitgestellte Objekt auf ein neues Objekt.    Mehr auf mdn

Hinweis: Verbreitung Syntax in Objektliterale funktioniert nicht in Rand- und IE und es ist eine experimentelle Funktion. Browser-Kompatibilität

Die erste Option wirklich verdient Aufmerksamkeit weil es das ist, was ich habe in ziemlich komplexen Code-Setup kommen. Also, meine Antwort ist

  
      
  1. Mit verschiedenen Namen in erster Linie
  2.   

Mit einem wenig, aber wesentlichem Hinweis, sollten Namen für Computer anders aussehen, aber nicht für Sie. Name des überladenen Funktionen wie:. Func, func1, func2

Dies ist eine alte Frage, aber eine, die ich Bedarf eines weiteren Eintrag denke (obwohl ich jemand bezweifeln, liest es). Die Verwendung von sofort aufgerufen Funktion Expressions (IIFE) mit Verschlüssen und Inline-Funktionen in Verbindung verwendet werden, für die Funktion Überlastung zu ermöglichen. Betrachten Sie die folgende (erfundene) Beispiel:

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

Kurz gesagt, die Verwendung des IIFE erzeugt einen lokalen Bereich, so dass wir die private Variable old definieren, einen Verweis auf die ursprüngliche Definition der Funktion foo zu speichern. Diese Funktion gibt dann eine Inline-Funktion newFoo, die den Inhalt beider zwei Argumente protokolliert, wenn es übergeben wird genau zwei Argumente a und b oder ruft die old Funktion, wenn arguments.length !== 2. Dieses Muster kann beliebig oft wiederholt werden, um eine Variable mit mehreren verschiedenen funktionellen defitions zu verleihen.

JavaScript ist nicht typisierte Sprache, und ich denke nur, dass Sinn, eine Methode / Funktion in Bezug auf die Anzahl der params zu überlasten macht. Daher würde ich empfehlen, wenn der Parameter zu überprüfen definiert wurde:

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

Im Juli 2017 hat sich die im Anschluss an die übliche Technik gewesen. Beachten Sie, dass wir auch die Typprüfung in der Funktion.

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

Für Ihren Anwendungsfall, das ist, wie ich es mit ES6 angehen würde (da es bereits Ende 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;
}

Sie können dies natürlich anpassen mit jeder Menge von Parametern zu arbeiten und nur entsprechend Ihre bedingten Anweisungen ändern.

So etwas kann für die Funktion Überlastung erfolgen.

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

Quelle

Wir haben over.js dieses Problem zu lösen, eine sehr elegante Art und Weise ist. Sie tun können:

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 mochte ich wirklich diese Art und Weise, Dinge zu tun, die ich in Geheimnisse der Javascript ninja gefunden

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

Sie dann addMethod verwenden, um überladene Funktionen zu einem Objekt hinzufügen. Die Haupt Verwirrung in diesem Code für mich war die Verwendung von fn.length == arguments.length - dies funktioniert, weil fn.length die Anzahl der erwarteten Parameter, während arguments.length die Anzahl der Parameter ist, die mit der tatsächlich aufgerufen werden Funktion. Der Grund für die anonyme Funktion kein Argument hat, weil man in einer beliebigen Anzahl von Argumenten in Javascript, und die Sprache ist nachsichtig passieren kann.

Ich mochte dies, weil Sie es überall verwenden können - nur diese Funktion erstellen und verwenden Sie einfach die Methode in welcher Codebasis Sie wollen.

Es vermeidet auch eine lächerlich große mit if / switch-Anweisung, die, wenn Sie lesen hart wird komplexen Code Schreiben beginnen (die akzeptierte Antwort wird in dieser Folge).

Im Hinblick auf die Nachteile, ich denke, der Code zunächst ein wenig dunkel ist ... aber ich bin anderer nicht sicher?

Ich möchte ein nützliches Beispiel für überladene artigen Ansatz teilen.

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

Verbrauch:   Klar(); // Löscht alle das Dokument

Clear (myDiv); // Clears Panel von myDiv verwiesen

Ich mag @ AntouanK Ansatz. Ich finde ich oft eine Funktion mit verschiedenen Zahlen o Parametern und verschiedenen Typen anbieten. Manchmal folgen sie keinen Auftrag. Ich benutze zur Karte der Parametertypen suchen:

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);
}
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top