Question Fonction de surcharge en Javascript - Bonnes pratiques


Quel est le meilleur moyen de fausser la surcharge de Javascript?

Je sais qu'il n'est pas possible de surcharger les fonctions en Javascript comme dans d'autres langues. Si j'avais besoin d'une fonction avec deux utilisations foo(x) et foo(x,y,z) qui est le meilleur / préféré

  1. En utilisant des noms différents en premier lieu
  2. En utilisant des arguments facultatifs comme y = y || 'default'
  3. En utilisant le nombre d'arguments
  4. Vérification des types d'arguments
  5. Ou comment?

647
2018-01-19 00:06


origine


Réponses:


La meilleure façon de surcharger les fonctions avec des paramètres n'est pas de vérifier la longueur de l'argument ou les types; vérifier les types ne fera que ralentir votre code et vous aurez l'amusement des tableaux, des zéros, des objets, etc.

Ce que font la plupart des développeurs, c'est d'utiliser un objet comme dernier argument de leurs méthodes. Cet objet peut contenir n'importe quoi.

function foo(a, b, opts) {

}


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

Ensuite, vous pouvez le gérer comme vous le souhaitez dans votre méthode. [Switch, if-else, etc.]


499
2018-01-19 13:32



Je fais souvent ceci:

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

Équivalent 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

Cet exemple particulier est en fait plus élégant en javascript que C #. Les paramètres qui ne sont pas spécifiés sont 'non définis' dans javascript, ce qui donne false dans une instruction if. Cependant, la définition de la fonction ne transmet pas l'information que p2 et p3 sont facultatifs. Si vous avez besoin de beaucoup de surcharge, jQuery a décidé d'utiliser un objet comme paramètre, par exemple, jQuery.ajax (options). Je suis d'accord avec eux pour dire que c'est l'approche la plus puissante et la plus documentable de la surcharge, mais j'ai rarement besoin de plus d'un ou deux paramètres optionnels rapides.

EDIT: modification du test IF par suggestion de Ian


141
2018-02-15 17:19



Il n'y a pas de surcharges de fonctions en JavaScript car cela permet de passer n'importe quel nombre de paramètres de n'importe quel type. Vous devez vérifier à l'intérieur de la fonction combien arguments ont été passés et de quel type ils sont.


56
2018-01-19 00:12



La bonne réponse est qu'il n'y a pas de surcharge dans JAVASCRIPT.

La vérification / commutation à l'intérieur de la fonction n'est pas OVERLOADING.

Le concept de surcharge: Dans certains langages de programmation, la surcharge de fonctions ou la surcharge de méthodes est la possibilité de créer plusieurs méthodes du même nom avec différentes implémentations. Les appels à une fonction surchargée exécuteront une implémentation spécifique de cette fonction appropriée au contexte de l'appel, permettant à un appel de fonction d'effectuer différentes tâches en fonction du contexte.

Par exemple, doTask () et doTask (objet O) sont des méthodes surchargées. Pour appeler ce dernier, un objet doit être passé en paramètre, alors que le premier ne nécessite pas de paramètre et est appelé avec un champ de paramètre vide. Une erreur courante consisterait à affecter une valeur par défaut à l'objet dans la seconde méthode, ce qui entraînerait une erreur d'appel ambiguë, car le compilateur ne saurait pas laquelle des deux méthodes utiliser.

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

Toutes les implémentations suggérées sont excellentes, mais à vrai dire, il n'y a pas d'implémentation native pour JavaScript.


35
2017-11-03 18:21



Il y a deux façons d'aborder cela mieux:

  1. Passez un dictionnaire (tableau associatif) si vous voulez laisser beaucoup de flexibilité

  2. Prenez un objet comme argument et utilisez l'héritage basé sur le prototype pour ajouter de la flexibilité.


25
2018-01-19 00:50



Voici un test de référence sur la surcharge de fonctions - http://goo.gl/UyYAD (code affiché dans ce post). Il montre que la surcharge de fonctions (prise en compte de types) peut être autour de 13 fois plus lent dans Google Le V8 de Chrome à partir de 16,0 (beta).

En plus de passer un objet (c.-à-d. {x: 0, y: 0}), on peut également adopter l'approche C, le cas échéant, en nommant les méthodes en conséquence. Par exemple, Vector.AddVector (vector), Vector.AddIntegers (x, y, z, ...) et Vector.AddArray (integerArray). Vous pouvez regarder les bibliothèques C, telles que OpenGL pour nommer l'inspiration.

modifier: J'ai ajouté une référence pour passer un objet et tester l'objet en utilisant à la fois 'param' in arg et arg.hasOwnProperty('param'), et la surcharge de fonction est beaucoup plus rapide que de passer un objet et de vérifier les propriétés (dans ce cas-ci au moins).

Du point de vue de la conception, la surcharge de fonction n'est valide ou logique que si les paramètres surchargés correspondent à la même action. Donc, il va de soi qu'il devrait y avoir une méthode sous-jacente qui ne concerne que des détails spécifiques, sinon cela pourrait indiquer des choix de conception inappropriés. Ainsi, on pourrait aussi résoudre l'utilisation de la surcharge de fonction en convertissant des données en un objet respectif. Bien sûr, il faut considérer la portée du problème car il n'est pas nécessaire de faire des conceptions élaborées si votre intention est simplement d'imprimer un nom, mais pour la conception de cadres et de bibliothèques, une telle pensée est justifiée.

Mon exemple provient d'une implémentation Rectangle - d'où la mention de Dimension et Point. Peut-être que Rectangle pourrait ajouter GetRectangle() méthode à la Dimension et Point prototype, puis le problème de surcharge de fonction est triée. Et qu'en est-il des primitives? Eh bien, nous avons la longueur de l'argument, qui est maintenant un test valide puisque les objets ont un GetRectangle() méthode.

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

16
2017-12-26 12:13



La meilleure façon dépend vraiment de la fonction et des arguments. Chacune de vos options est une bonne idée dans différentes situations. Je les essaye généralement dans l'ordre suivant jusqu'à ce que l'un d'entre eux fonctionne:

  1. En utilisant des arguments optionnels comme y = y || 'défaut'. C'est pratique si vous pouvez le faire, mais cela ne fonctionne pas toujours, par ex. quand 0 / null / undefined serait un argument valide.

  2. En utilisant le nombre d'arguments. Semblable à la dernière option mais peut fonctionner lorsque # 1 ne fonctionne pas.

  3. Vérification des types d'arguments. Cela peut fonctionner dans certains cas où le nombre d'arguments est le même. Si vous ne pouvez pas déterminer de manière fiable les types, vous devrez peut-être utiliser des noms différents.

  4. En utilisant des noms différents en premier lieu. Vous devrez peut-être faire cela si les autres options ne fonctionnent pas, ne sont pas pratiques, ou pour la cohérence avec d'autres fonctions connexes.


13
2018-01-19 01:30



Si j'avais besoin d'une fonction avec deux utilisations foo (x) et foo (x, y, z) qui est le meilleur / préféré?

Le problème est que JavaScript ne supporte pas nativement la surcharge des méthodes. Donc, s'il voit / analyse deux ou plusieurs fonctions avec un même nom, il considérera simplement la dernière fonction définie et écrasera les précédentes.

Une des façons dont je pense est approprié pour la plupart de l'affaire est la suivante -

Disons que vous avez une méthode

function foo(x)
{
} 

Au lieu de la méthode de surcharge ce qui n'est pas possible en javascript vous pouvez définir une nouvelle méthode

fooNew(x,y,z)
{
}

puis modifiez la première fonction comme suit -

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

Si vous avez beaucoup de telles méthodes surchargées envisager d'utiliser switch Que juste if-else déclarations.

(plus de détails)


11
2017-09-13 06:44