Pregunta Sobrecarga de funciones en Javascript - Mejores prácticas


¿Cuál es la mejor manera de falsificar la sobrecarga de funciones en Javascript?

Sé que no es posible sobrecargar funciones en Javascript como en otros idiomas. Si necesitaba una función con dos usos foo(x) y foo(x,y,z) cuál es la mejor / preferida forma:

  1. Usar diferentes nombres en primer lugar
  2. Usando argumentos opcionales como y = y || 'default'
  3. Usando la cantidad de argumentos
  4. Verificando tipos de argumentos
  5. ¿O como?

647
2018-01-19 00:06


origen


Respuestas:


La mejor manera de sobrecargar la función con parámetros es no verificar la longitud del argumento o los tipos; comprobar los tipos hará que su código sea lento y se divierta con Arrays, nulls, Objects, etc.

Lo que la mayoría de los desarrolladores hacen es virar en un objeto como el último argumento para sus métodos. Este objeto puede contener cualquier cosa.

function foo(a, b, opts) {

}


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

Entonces puedes manejarlo de la forma que quieras en tu método. [Cambiar, if-else, etc.]


499
2018-01-19 13:32



A menudo hago esto:

DO#:

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

Este ejemplo particular es realmente más elegante en javascript que C #. Los parámetros que no se especifican están 'indefinidos' en javascript, que se evalúa como falso en una sentencia if. Sin embargo, la definición de la función no transmite la información de que p2 y p3 son opcionales. Si necesita mucha sobrecarga, jQuery ha decidido usar un objeto como parámetro, por ejemplo, jQuery.ajax (opciones). Estoy de acuerdo con ellos en que este es el enfoque más poderoso y claramente documentable para la sobrecarga, pero rara vez necesito más de uno o dos parámetros opcionales rápidos.

EDITAR: cambio de la prueba IF según la sugerencia de Ian


141
2018-02-15 17:19



No existe una sobrecarga de función real en JavaScript, ya que permite pasar cualquier cantidad de parámetros de cualquier tipo. Debes verificar dentro de la función cuántos argumentos han sido aprobados y de qué tipo son.


56
2018-01-19 00:12



La respuesta correcta es NO HAY SOBRECARGA EN JAVASCRIPT.

Verificación / cambio dentro de la función no es SOBRECARGA.

El concepto de sobrecarga: En algunos lenguajes de programación, la sobrecarga de funciones o la sobrecarga de métodos es la capacidad de crear múltiples métodos del mismo nombre con diferentes implementaciones. Las llamadas a una función sobrecargada ejecutarán una implementación específica de esa función apropiada para el contexto de la llamada, lo que permite que una llamada a función realice diferentes tareas según el contexto.

Por ejemplo, doTask () y doTask (objeto O) son métodos sobrecargados. Para llamar a este último, un objeto debe pasarse como un parámetro, mientras que el primero no requiere un parámetro, y se llama con un campo de parámetro vacío. Un error común sería asignar un valor predeterminado al objeto en el segundo método, lo que daría como resultado un error de llamada ambiguo, ya que el compilador no sabría cuál de los dos métodos usar.

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

Todas las implementaciones sugeridas son geniales, pero a decir verdad, no existe una implementación nativa para JavaScript.


35
2017-11-03 18:21



Hay dos formas de acercarte mejor a esto:

  1. Pase un diccionario (matriz asociativa) si quiere dejar mucha flexibilidad

  2. Tome un objeto como argumento y use la herencia basada en prototipos para agregar flexibilidad.


25
2018-01-19 00:50



Aquí hay una prueba de referencia sobre la sobrecarga de funciones: http://goo.gl/UyYAD (código que se muestra en esta publicación). Muestra que la sobrecarga de funciones (tomando tipos en cuenta) puede estar alrededor 13 veces más lento en Google V8 de Chrome a partir de 16.0 (beta).

Además de pasar un objeto (es decir {x: 0, y: 0}), también se puede tomar el enfoque C cuando sea apropiado, nombrando los métodos en consecuencia. Por ejemplo, Vector.AddVector (vector), Vector.AddIntegers (x, y, z, ...) y Vector.AddArray (integerArray). Puede ver las bibliotecas C, como OpenGL para nombrar la inspiración.

Editar: He agregado un punto de referencia para pasar un objeto y probar el objeto usando ambos 'param' in arg y arg.hasOwnProperty('param')y la sobrecarga de funciones es mucho más rápida que pasar un objeto y buscar propiedades (al menos en este punto de referencia).

Desde una perspectiva de diseño, la sobrecarga de funciones solo es válida o lógica si los parámetros sobrecargados corresponden a la misma acción. Por lo tanto, es lógico pensar que debe haber un método subyacente que solo se ocupe de los detalles específicos, de lo contrario, puede indicar opciones de diseño inapropiadas. De modo que también se podría resolver el uso de la sobrecarga de funciones convirtiendo datos a un objeto respectivo. Por supuesto, uno debe considerar el alcance del problema ya que no hay necesidad de hacer diseños elaborados si su intención es simplemente imprimir un nombre, pero para el diseño de marcos y bibliotecas ese pensamiento está justificado.

Mi ejemplo proviene de una implementación Rectangle, de ahí la mención de Dimension and Point. Quizás Rectangle podría agregar un GetRectangle() método a la Dimension y Point prototipo, y luego el problema de sobrecarga de funciones está ordenado. ¿Y qué hay de los primitivos? Bueno, tenemos longitud de argumento, que ahora es una prueba válida ya que los objetos tienen una GetRectangle() método.

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 mejor manera realmente depende de la función y los argumentos. Cada una de tus opciones es una buena idea en diferentes situaciones. Por lo general, pruebo estos en el siguiente orden hasta que uno de ellos funcione:

  1. Usando argumentos opcionales como y = y || 'defecto'. Esto es conveniente si puede hacerlo, pero puede no funcionar siempre de manera práctica, p. cuando 0 / null / undefined sería un argumento válido.

  2. Usando la cantidad de argumentos. Similar a la última opción, pero puede funcionar cuando el # 1 no funciona.

  3. Verificando tipos de argumentos. Esto puede funcionar en algunos casos donde la cantidad de argumentos es la misma. Si no puede determinar los tipos de manera confiable, es posible que necesite usar diferentes nombres.

  4. Usar diferentes nombres en primer lugar. Es posible que deba hacer esto si las otras opciones no funcionan, no son prácticas o si son coherentes con otras funciones relacionadas.


13
2018-01-19 01:30