Pregunta ¿Hay una mejor manera de hacer los parámetros de funciones opcionales en JavaScript? [duplicar]


Esta pregunta ya tiene una respuesta aquí:

Siempre he manejado parámetros opcionales en JavaScript como este:

function myFunc(requiredArg, optionalArg){
  optionalArg = optionalArg || 'defaultValue';

  // Do stuff
}

Hay una mejor manera de hacerlo?

¿Hay algún caso donde usar || como que va a fallar?


756
2017-09-29 14:27


origen


Respuestas:


Su lógica falla si se pasa opcionalArg, pero se evalúa como falso: intente esto como una alternativa

if (typeof optionalArg === 'undefined') { optionalArg = 'default'; }

O un modismo alternativo:

optionalArg = (typeof optionalArg === 'undefined') ? 'default' : optionalArg;

¡Utiliza el idioma que mejor te convenga!


1012
2017-09-29 14:30



Encuentro que esta es la forma más simple y más legible:

if (typeof myVariable === 'undefined') { myVariable = 'default'; }
//use myVariable here

La respuesta de Paul Dixon (en mi humilde opinión) es menos legible que esto, pero todo se reduce a las preferencias.

La respuesta de Insin es mucho más avanzada, ¡pero mucho más útil para grandes funciones!

EDITAR 17/11/2013 9:33 p.m .: Creé un paquete para Node.js que hace que sea más fácil "sobrecargar" las funciones (métodos) llamadas paramétrico.


125
2017-11-14 21:23



En ECMAScript 2015 (también conocido como "ES6") puede declarar valores de argumento predeterminados en la declaración de la función:

function myFunc(requiredArg, optionalArg = 'defaultValue') {
    // do stuff
}

Más sobre ellos en este artículo en MDN (a pesar del título del artículo, se llaman "argumentos", no "parámetros", en JavaScript).

Esto es actualmente solo compatible con Firefox, pero a medida que se completa el estándar, se espera que el soporte mejore rápidamente.


119
2018-02-19 13:13



Si necesitas tirar un literal NULL adentro, entonces podrías tener algunos problemas. Aparte de eso, no, creo que probablemente estés en el camino correcto.

El otro método que algunas personas eligen es tomar una matriz de variables asociadas iterando a través de la lista de argumentos. Se ve un poco más ordenado, pero me imagino que es un poco (muy poco) poco más intenso de proceso / memoria.

function myFunction (argArray) {
    var defaults = {
        'arg1'  :   "value 1",
        'arg2'  :   "value 2",
        'arg3'  :   "value 3",
        'arg4'  :   "value 4"
    }

    for(var i in defaults) 
        if(typeof argArray[i] == "undefined") 
               argArray[i] = defaults[i];

    // ...
}

44
2017-09-29 14:34



Idealmente, se refactorizaría para pasar un objeto y unir con un objeto predeterminado, por lo que el orden en que se pasan los argumentos no importa (ver la segunda sección de esta respuesta, más abajo).

Sin embargo, si solo quiere algo rápido, confiable, fácil de usar y no voluminoso, intente esto:


Una solución rápida y limpia para cualquier cantidad de argumentos predeterminados

  • Escala elegantemente: código adicional mínimo para cada nuevo valor predeterminado
  • Puede pegarlo en cualquier lugar: simplemente cambie el número de args y variables necesarios
  • Si quieres pasar undefined a un argumento con un valor predeterminado, de esta manera, la variable se establece como undefined. La mayoría de las otras opciones en esta página reemplazarían undefined con el valor predeterminado.

Aquí hay un ejemplo para proporcionar valores predeterminados para tres argumentos opcionales (con dos argumentos requeridos)

function myFunc( requiredA, requiredB,  optionalA, optionalB, optionalC ) {

  switch (arguments.length - 2) { // 2 is the number of required arguments
    case 0:  optionalA = 'Some default';
    case 1:  optionalB = 'Another default';
    case 2:  optionalC = 'Some other default';
    // no breaks between cases: each case implies the next cases are also needed
  }

}

Demostración simple. Esto es similar a La respuesta de roenving, pero fácilmente extensible para cualquier cantidad de argumentos predeterminados, más fácil de actualizar y utilizando arguments no Function.arguments.


Pasar y fusionar objetos para una mayor flexibilidad

El código anterior, como muchas formas de hacer argumentos predeterminados, no puede pasar los argumentos fuera de secuencia, por ejemplo, pasar optionalCpero dejando optionalB volver a su estado predeterminado.

Una buena opción para eso es pasar objetos y fusionar con un objeto predeterminado. Esto también es bueno para la mantenibilidad (solo tenga cuidado de mantener su código legible, para que los futuros colaboradores no se queden adivinando sobre los posibles contenidos de los objetos que pasa).

Ejemplo usando jQuery. Si no usas jQuery, podrías usar UnderScore _.defaults(object, defaults) o navegar por estas opciones:

function myFunc( args ) {
  var defaults = {
    optionalA: 'Some default',
    optionalB: 'Another default',
    optionalC: 'Some other default'
  };
  args = $.extend({}, defaults, args);
}

Aquí está un simple ejemplo de ello en acción.


32
2018-02-20 15:36



Puedes usar algunos esquemas diferentes para eso. Siempre he probado argumentos.length:

function myFunc(requiredArg, optionalArg){
  optionalArg = myFunc.arguments.length<2 ? 'defaultValue' : optionalArg;

  ...

- Al hacerlo, posiblemente no puede fallar, pero no sé si tu camino tiene alguna posibilidad de fallar, ahora no puedo pensar en un escenario, donde en realidad podría fallar ...

¡Y luego Paul proporcionó un escenario fallido! -)


17
2017-09-29 14:33



Al igual que en la respuesta de Oli, utilizo un argumento Object y un Object que define los valores predeterminados. Con un poco de azúcar ...

/**
 * Updates an object's properties with other objects' properties. All
 * additional non-falsy arguments will have their properties copied to the
 * destination object, in the order given.
 */
function extend(dest) {
  for (var i = 1, l = arguments.length; i < l; i++) {
    var src = arguments[i]
    if (!src) {
      continue
    }
    for (var property in src) {
      if (src.hasOwnProperty(property)) {
        dest[property] = src[property]
      }
    }
  }
  return dest
}

/**
 * Inherit another function's prototype without invoking the function.
 */
function inherits(child, parent) {
  var F = function() {}
  F.prototype = parent.prototype
  child.prototype = new F()
  child.prototype.constructor = child
  return child
}

... esto se puede hacer un poco mejor.

function Field(kwargs) {
  kwargs = extend({
    required: true, widget: null, label: null, initial: null,
    helpText: null, errorMessages: null
  }, kwargs)
  this.required = kwargs.required
  this.label = kwargs.label
  this.initial = kwargs.initial
  // ...and so on...
}

function CharField(kwargs) {
  kwargs = extend({
    maxLength: null, minLength: null
  }, kwargs)
  this.maxLength = kwargs.maxLength
  this.minLength = kwargs.minLength
  Field.call(this, kwargs)
}
inherits(CharField, Field)

¿Qué tiene de bueno este método?

  • Puede omitir todos los argumentos que desee; si solo desea anular el valor de un argumento, puede proporcionar ese argumento, en lugar de tener que pasar explícitamente undefined cuando, digamos que hay 5 argumentos y solo quieres personalizar el último, como lo harías con algunos de los otros métodos sugeridos.
  • Cuando se trabaja con una función de constructor para un objeto que hereda de otra, es fácil aceptar cualquier argumento que requiera el constructor del objeto que está heredando, ya que no tiene que nombrar esos argumentos en la firma de su constructor. o incluso proporcione sus propios valores predeterminados (deje que el constructor del Objeto padre haga eso por usted, como se ve arriba cuando CharField llamadas Fieldconstructor de)
  • Los objetos secundarios en las jerarquías de herencia pueden personalizar los argumentos para su constructor padre como mejor les parezca, imponiendo sus propios valores predeterminados o asegurando que un determinado valor siempre ser usado.

13
2017-09-29 23:16