¿Hay una mejor manera de hacer parámetros de función opcionales en JavaScript? [duplicar]

StackOverflow https://stackoverflow.com/questions/148901

  •  02-07-2019
  •  | 
  •  

Pregunta

    

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 en el que el uso de || como ese vaya a fallar?

¿Fue útil?

Solución

Tu lógica falla si se aprueba opcionalArg, pero se evalúa como falsa. Prueba esto como una alternativa

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

O un idioma alternativo:

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

¡Usa el idioma que te comunique la mejor intención!

Otros consejos

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

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

Más sobre ellos en este artículo en MDN .

Esto actualmente es solo compatible con Firefox , pero como el estándar se ha completado, espere que el soporte mejore rápidamente.

EDITAR (2019-06-12):

Los parámetros predeterminados ahora son ampliamente compatibles con los navegadores modernos. Todas las versiones de Internet Explorer no admiten esta función. Sin embargo, Chrome, Firefox y Edge actualmente lo admiten.

Considero que esta es la forma más sencilla y fácil de leer:

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 se reduce a la preferencia.

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

EDITAR 11/17/2013 9:33 pm: he creado un paquete para Node.js que hace que sea más fácil " sobrecargar " funciones (métodos) llamadas parametric .

Si necesita mandar un NULL literal, entonces podría 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 gran variedad de variables iterando a través de la lista de argumentos. Se ve un poco más ordenado, pero me imagino que requiere un poco más (un poco) más 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];

    // ...
}

Lo ideal sería refactorizar para pasar un objeto y fusionarlo con un objeto predeterminado, por lo que el orden en el que se pasan los argumentos no importa (consulte la segunda sección de esta respuesta, a continuación).

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


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

  • Escala con elegancia: código extra mínimo para cada nuevo valor predeterminado
  • Puede pegarlo en cualquier lugar: simplemente cambie el número de argumentos y variables requeridos
  • Si desea pasar undefined a un argumento con un valor predeterminado, de esta manera, la variable se establece como undefined . La mayoría de las demás opciones en esta página reemplazarán a undefined con el valor predeterminado.

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

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 se puede extender fácilmente a cualquier número de argumentos predeterminados, más fácil de actualizar y usando argumentos no Function.arguments .


Pasar y fusionar objetos para una mayor flexibilidad

El código anterior, al igual que muchas formas de hacer argumentos predeterminados, no puede pasar los argumentos fuera de secuencia, por ejemplo, pasar optionalC pero dejando optionalB para volver a su defecto.

Una buena opción para eso es pasar objetos y combinarlos con un objeto predeterminado. Esto también es bueno para la capacidad de mantenimiento (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 usa jQuery, podría usar _.defaults (objeto, valores predeterminados) o navegue 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 ejemplo simple de ello en acción .

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 manera tiene alguna posibilidad de fallar, ahora mismo no puedo pensar en un escenario, donde realmente podría fallar ...

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

Similar a la respuesta de Oli, uso 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 más agradable.

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 tantos argumentos como 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 allí son 5 argumentos y solo desea personalizar el último, ya que tendría que ver con algunos de los otros métodos sugeridos.
  • Al trabajar con una función constructora para un objeto que hereda de otro, es fácil aceptar cualquier argumento que requiera el constructor del objeto del que está heredando, ya que no tiene que nombrar esos argumentos en su firma del constructor, o incluso proporcione sus propios valores predeterminados (deje que el constructor del objeto padre lo haga por usted, como se ve arriba cuando CharField llama al constructor de Field ).
  • Los objetos secundarios en las jerarquías de herencia pueden personalizar los argumentos para su constructor principal como mejor les parezca, imponiendo sus propios valores predeterminados o garantizando que se utilizará un determinado valor siempre .

Si usa valores predeterminados ampliamente, esto parece mucho más legible:

function usageExemple(a,b,c,d){
    //defaults
    a=defaultValue(a,1);
    b=defaultValue(b,2);
    c=defaultValue(c,4);
    d=defaultValue(d,8);

    var x = a+b+c+d;
    return x;
}

Simplemente declare esta función en el ámbito global.

function defaultValue(variable,defaultValue){
    return(typeof variable!=='undefined')?(variable):(defaultValue);
}

Patrón de uso fruit = defaultValue (fruit, 'Apple');

* PD: puede cambiar el nombre de la función defaultValue a un nombre corto, simplemente no use default es una palabra reservada en javascript.

Comprobación de tipo suelto

Fácil de escribir, pero 0 , '' , false , null y undefined se convertirá al valor predeterminado, que podría no ser el resultado esperado.

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

Verificación estricta de tipos

Más largo, pero cubre la mayoría de los casos. El único caso en el que asigna incorrectamente el valor predeterminado es cuando pasamos undefined como parámetro.

function myFunc(requiredArg, optionalArg) {
    optionalArg = typeof optionalArg !== 'undefined' ? optionalArg : 'defaultValue';
}

Comprobando la variable de argumentos

Captura todos los casos pero es el más torpe para escribir.

function myFunc(requiredArg, optionalArg1, optionalArg2) {
    optionalArg1 = arguments.length > 1 ? optionalArg1 : 'defaultValue';
    optionalArg2 = arguments.length > 2 ? optionalArg2 : 'defaultValue';
}

ES6

Desafortunadamente, este es un soporte de navegador muy pobre en este momento

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

}

Con ES2015 / ES6 puede aprovechar Object.assign que puede reemplazar $ .extend () o _.defaults ()

function myFunc(requiredArg, options = {}) {
  const defaults = {
    message: 'Hello',
    color: 'red',
    importance: 1
  };

  const settings = Object.assign({}, defaults, options);

  // do stuff
}

También puedes usar argumentos predeterminados como este

function myFunc(requiredArg, { message: 'Hello', color: 'red', importance: 1 } = {}) {
  // do stuff
}

Estoy acostumbrado a ver algunas variaciones básicas en el manejo de variables opcionales. A veces, las versiones relajadas son útiles.

function foo(a, b, c) {
  a = a || "default";   // Matches 0, "", null, undefined, NaN, false.
  a || (a = "default"); // Matches 0, "", null, undefined, NaN, false.

  if (b == null) { b = "default"; } // Matches null, undefined.

  if (typeof c === "undefined") { c = "default"; } // Matches undefined.
}

El valor predeterminado de falsy utilizado con la variable a se usa ampliamente en Backbone.js .

Si está utilizando la subrayado biblioteca (debería, es una biblioteca increíble):

_.defaults(optionalArg, 'defaultValue');

Llegó a esta pregunta, buscando parámetros predeterminados en EcmaScript 2015 , solo mencionando ...

Con ES6 podemos hacer parámetros predeterminados :

function doSomething(optionalParam = "defaultValue"){
    console.log(optionalParam);//not required to check for falsy values
}

doSomething(); //"defaultValue"
doSomething("myvalue"); //"myvalue"

Durante un proyecto, noté que me repetía demasiado con los parámetros y configuraciones opcionales, así que hice una clase que maneja la verificación de tipos y asigna un valor predeterminado que da como resultado un código limpio y legible. Vea el ejemplo y avíseme si esto funciona para usted.

var myCar           = new Car('VW', {gearbox:'automatic', options:['radio', 'airbags 2x']});
var myOtherCar      = new Car('Toyota');

function Car(brand, settings) {
    this.brand      = brand;

    // readable and adjustable code
    settings        = DefaultValue.object(settings, {});
    this.wheels     = DefaultValue.number(settings.wheels, 4);
    this.hasBreaks  = DefaultValue.bool(settings.hasBreaks, true);
    this.gearbox    = DefaultValue.string(settings.gearbox, 'manual');
    this.options    = DefaultValue.array(settings.options, []);

    // instead of doing this the hard way
    settings        = settings || {};
    this.wheels     = (!isNaN(settings.wheels)) ? settings.wheels : 4;
    this.hasBreaks  = (typeof settings.hasBreaks !== 'undefined') ? (settings.hasBreaks === true) : true;
    this.gearbox    = (typeof settings.gearbox === 'string') ? settings.gearbox : 'manual';
    this.options    = (typeof settings.options !== 'undefined' && Array.isArray(settings.options)) ? settings.options : [];
}

Usando esta clase:

(function(ns) {

    var DefaultValue = {

        object: function(input, defaultValue) {
            if (typeof defaultValue !== 'object') throw new Error('invalid defaultValue type');
            return (typeof input !== 'undefined') ? input : defaultValue;
        },

        bool: function(input, defaultValue) {
            if (typeof defaultValue !== 'boolean') throw new Error('invalid defaultValue type');
            return (typeof input !== 'undefined') ? (input === true) : defaultValue;
        },

        number: function(input, defaultValue) {
            if (isNaN(defaultValue)) throw new Error('invalid defaultValue type');
            return (typeof input !== 'undefined' && !isNaN(input)) ? parseFloat(input) : defaultValue;
        },

        // wrap the input in an array if it is not undefined and not an array, for your convenience
        array: function(input, defaultValue) {
            if (typeof defaultValue === 'undefined') throw new Error('invalid defaultValue type');
            return (typeof input !== 'undefined') ? (Array.isArray(input) ? input : [input]) : defaultValue;
        },

        string: function(input, defaultValue) {
            if (typeof defaultValue !== 'string') throw new Error('invalid defaultValue type');
            return (typeof input === 'string') ? input : defaultValue;
        },

    };

    ns.DefaultValue = DefaultValue;

}(this));

No sé por qué la respuesta de @ Paul es rechazada, pero la validación contra null es una buena opción. Quizás un ejemplo más afirmativo tenga más sentido:

En JavaScript, un parámetro perdido es como una variable declarada que no se inicializa (solo var a1; ). Y el operador de igualdad convierte lo indefinido en nulo, por lo que funciona muy bien con los tipos de valor y los objetos, y así es como CoffeeScript maneja los parámetros opcionales.

function overLoad(p1){
    alert(p1 == null); // Caution, don't use the strict comparison: === won't work.
    alert(typeof p1 === 'undefined');
}

overLoad(); // true, true
overLoad(undefined); // true, true. Yes, undefined is treated as null for equality operator.
overLoad(10); // false, false


function overLoad(p1){
    if (p1 == null) p1 = 'default value goes here...';
    //...
}

Sin embargo, existe la preocupación de que, para la mejor semántica, typeof variable === 'undefined' es un poco mejor. No estoy dispuesto a defender esto, ya que es la cuestión de la API subyacente cómo se implementa una función; no debe interesar al usuario de la API.

También debo agregar que esta es la única manera de asegurarse físicamente de que se pierda cualquier argumento, utilizando el operador in que desafortunadamente no funcionará con los nombres de los parámetros, por lo que debe pasar un índice del argumentos .

function foo(a, b) {
    // Both a and b will evaluate to undefined when used in an expression
    alert(a); // undefined
    alert(b); // undefined

    alert("0" in arguments); // true
    alert("1" in arguments); // false
}

foo (undefined);

La prueba para undefined es innecesaria y no es tan robusta como podría ser porque, como señaló el usuario 568458, la solución provista falla si se pasa nulo o falso. Los usuarios de su API pueden pensar que falso o nulo forzarían el método para evitar ese parámetro.

function PaulDixonSolution(required, optionalArg){
   optionalArg = (typeof optionalArg === "undefined") ? "defaultValue" : optionalArg;
   console.log(optionalArg);
};
PaulDixonSolution("required");
PaulDixonSolution("required", "provided");
PaulDixonSolution("required", null);
PaulDixonSolution("required", false);

El resultado es:

defaultValue
provided
null
false

Los dos últimos son potencialmente malos. En su lugar, intente:

function bulletproof(required, optionalArg){
   optionalArg = optionalArg ? optionalArg : "defaultValue";;
   console.log(optionalArg);
};
bulletproof("required");
bulletproof("required", "provided");
bulletproof("required", null);
bulletproof("required", false);

Lo que resulta en:

defaultValue
provided
defaultValue
defaultValue

El único escenario donde esto no es óptimo es cuando realmente tiene parámetros opcionales que están destinados a ser booleanos o nulos intencionales.

Probé algunas de las opciones mencionadas aquí y el rendimiento las probé. En este momento, el logicor parece ser el más rápido. Aunque esto está sujeto a cambios a lo largo del tiempo (diferentes versiones del motor JavaScript).

Estos son mis resultados (Microsoft Edge 20.10240.16384.0):

Function executed            Operations/sec     Statistics
TypeofFunction('test');          92,169,505     ±1.55%   9% slower
SwitchFuntion('test');            2,904,685     ±2.91%  97% slower
ObjectFunction({param1: 'test'});   924,753     ±1.71%  99% slower
LogicalOrFunction('test');      101,205,173     ±0.92%     fastest
TypeofFunction2('test');         35,636,836     ±0.59%  65% slower

Esta prueba de rendimiento se puede replicar fácilmente en: http://jsperf.com/optional-parameters-typeof-vs-switch/ 2

Este es el código de la prueba:

<script src="https://ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js"></script>
<script>
    Benchmark.prototype.setup = function() {
        function TypeofFunction(param1, optParam1, optParam2, optParam3) {
            optParam1 = (typeof optParam1 === "undefined") ? "Some default" : optParam1;
            optParam2 = (typeof optParam2 === "undefined") ? "Another default" : optParam2;
            optParam3 = (typeof optParam3 === "undefined") ? "Some other default" : optParam3;
        }

        function TypeofFunction2(param1, optParam1, optParam2, optParam3) {
            optParam1 = defaultValue(optParam1, "Some default");
            optParam2 = defaultValue(optParam2, "Another default");
            optParam3 = defaultValue(optParam3, "Some other default");
        }

        function defaultValue(variable, defaultValue) {
            return (typeof variable !== 'undefined') ? (variable) : (defaultValue);
        }

        function SwitchFuntion(param1, optParam1, optParam2, optParam3) {
            switch (arguments.length - 1) { // <-- 1 is number of required arguments
                case 0:
                    optParam1 = 'Some default';
                case 1:
                    optParam2 = 'Another default';
                case 2:
                    optParam3 = 'Some other default';
            }
        }

        function ObjectFunction(args) {
            var defaults = {
                optParam1: 'Some default',
                optParam2: 'Another default',
                optParam3: 'Some other default'
            }
            args = $.extend({}, defaults, args);
        }

        function LogicalOrFunction(param1, optParam1, optParam2, optParam3) {
            optParam1 || (optParam1 = 'Some default');
            optParam2 || (optParam1 = 'Another default');
            optParam3 || (optParam1 = 'Some other default');
        }
    };
</script>

Esto es lo que terminé con:

function WhoLikesCake(options) {
  options = options || {};
  var defaultOptions = {
    a : options.a || "Huh?",
    b : options.b || "I don't like cake."
  }
  console.log('a: ' + defaultOptions.b + ' - b: ' + defaultOptions.b);

  // Do more stuff here ...
}

Llamado así:

WhoLikesCake({ b : "I do" });

Gente -

Después de mirar estas y otras soluciones, probé varias usando un fragmento de código originalmente de W3Schools como base. Puede encontrar lo que funciona en lo siguiente. Cada uno de los elementos comentados también funciona y es esa forma de permitirle experimentar simplemente eliminando comentarios individuales. Para ser claros, es el "color de ojos". parámetro que no se está definiendo.

function person(firstname, lastname, age, eyecolor)
{
this.firstname = firstname;
this.lastname = lastname;
this.age = age;
this.eyecolor = eyecolor;
// if(null==eyecolor)
//   this.eyecolor = "unknown1";
//if(typeof(eyecolor)==='undefined') 
//   this.eyecolor = "unknown2";
// if(!eyecolor)
//   this.eyecolor = "unknown3";
this.eyecolor = this.eyecolor || "unknown4";
}

var myFather = new person("John", "Doe", 60);
var myMother = new person("Sally", "Rally", 48, "green");

var elem = document.getElementById("demo");
elem.innerHTML = "My father " +
              myFather.firstname + " " +
              myFather.lastname + " is " +
              myFather.age + " with " +
              myFather.eyecolor + " eyes.<br/>" +
              "My mother " +
              myMother.firstname + " " +
              myMother.lastname + " is " +
              myMother.age + " with " +
              myMother.eyecolor + " eyes."; 
function Default(variable, new_value)
{
    if(new_value === undefined) { return (variable === undefined) ? null : variable; }
    return (variable === undefined) ? new_value : variable;
}

var a = 2, b = "hello", c = true, d;

var test = Default(a, 0),
test2 = Default(b, "Hi"),
test3 = Default(c, false),
test4 = Default(d, "Hello world");

window.alert(test + "\n" + test2 + "\n" + test3 + "\n" + test4);

http://jsfiddle.net/mq60hqrf/

Aquí está mi solución. Con esto puedes dejar cualquier parámetro que quieras. El orden de los parámetros opcionales no es importante y puede agregar una validación personalizada.

function YourFunction(optionalArguments) {
            //var scope = this;

            //set the defaults
            var _value1 = 'defaultValue1';
            var _value2 = 'defaultValue2';
            var _value3 = null;
            var _value4 = false;

            //check the optional arguments if they are set to override defaults...
            if (typeof optionalArguments !== 'undefined') {

                if (typeof optionalArguments.param1 !== 'undefined')
                    _value1 = optionalArguments.param1;

                if (typeof optionalArguments.param2 !== 'undefined')
                    _value2 = optionalArguments.param2;

                if (typeof optionalArguments.param3 !== 'undefined')
                    _value3 = optionalArguments.param3;

                if (typeof optionalArguments.param4 !== 'undefined')
                    //use custom parameter validation if needed, in this case for javascript boolean
                   _value4 = (optionalArguments.param4 === true || optionalArguments.param4 === 'true');
            }

            console.log('value summary of function call:');
            console.log('value1: ' + _value1);
            console.log('value2: ' + _value2);
            console.log('value3: ' + _value3);
            console.log('value4: ' + _value4);
            console.log('');
        }


        //call your function in any way you want. You can leave parameters. Order is not important. Here some examples:
        YourFunction({
            param1: 'yourGivenValue1',
            param2: 'yourGivenValue2',
            param3: 'yourGivenValue3',
            param4: true,
        });

        //order is not important
        YourFunction({
            param4: false,
            param1: 'yourGivenValue1',
            param2: 'yourGivenValue2',
        });

        //uses all default values
        YourFunction();

        //keeps value4 false, because not a valid value is given
        YourFunction({
            param4: 'not a valid bool'
        });
  1. arg || 'default' es una excelente manera y funciona para el 90% de los casos

  2. Falla cuando necesita pasar valores que podrían ser 'falsos'

    • false
    • 0
    • NaN
    • ""

    Para estos casos, deberá ser un poco más detallado y buscar undefined

  3. También tenga cuidado cuando primero tiene argumentos opcionales, debe conocer los tipos de todos sus argumentos

En todos los casos en los que el método opcional es falso, terminará con el valor predeterminado.

function myFunc(requiredArg, optionalArg) {
    optionalArg = optionalArg || 'defaultValue';
    console.log(optionalArg);
    // Do stuff
}
myFunc(requiredArg);
myFunc(requiredArg, null);
myFunc(requiredArg, undefined);
myFunc(requiredArg, "");
myFunc(requiredArg, 0);
myFunc(requiredArg, false);

Todos los valores predeterminados del registro anterior, porque todos los 6 son falsos. En los casos 4, 5, 6 puede que no esté interesado en establecer opcionalArg como valor predeterminado, pero se establece porque son falsos.

Corríjame si me equivoco, pero esta parece la forma más sencilla (para un argumento, de todos modos):

function myFunction(Required,Optional)
{
    if (arguments.length<2) Optional = "Default";
    //Your code
}

Esos son más cortos que la versión del operador de typeof.

function foo(a, b) {
    a !== undefined || (a = 'defaultA');
    if(b === undefined) b = 'defaultB';
    ...
}

Le sugiero que utilice ArgueJS de esta manera:

function myFunc(){
  arguments = __({requiredArg: undefined, optionalArg: [undefined: 'defaultValue'})

  //do stuff, using arguments.requiredArg and arguments.optionalArg
  //    to access your arguments

}

También puede reemplazar undefined por el tipo de argumento que espera recibir, como este:

function myFunc(){
  arguments = __({requiredArg: Number, optionalArg: [String: 'defaultValue'})

  //do stuff, using arguments.requiredArg and arguments.optionalArg
  //    to access your arguments

}

Parece que es la forma más segura: tratar con todos los \ cualquier tipos falsos de los argumentos proporcionados antes de decidir utilizar default - es verificar la existencia \ presencia del argumento opcional en la función invocada.

Confiando en los argumentos creación de miembro de objeto que ni siquiera se crea si falta el argumento, independientemente del hecho de que podría ser declarado, podemos escribir su función de esta manera:

  function myFunc(requiredArg, optionalArg){
        optionalArg = 1 in arguments ? optionalArg : 'defaultValue';
  //do stuff
  }

Utilizando este comportamiento: Podemos verificar con seguridad los valores faltantes en la lista de argumentos de manera arbitraria y explícita siempre que necesitemos asegurarnos de que la función obtenga un cierto valor requerido en su procedimiento.

En el siguiente código de demostración, pondremos deliberadamente un typeless y valueless undefined como valor predeterminado para ser capaz de determinar si puede fallar en valores de argumento falsos, como 0 falso, etc., o si se comporta como se espera.

function argCheck( arg1, arg2, arg3 ){

       arg1 = 0 in arguments || undefined;
       arg2 = 1 in arguments || false;
       arg3 = 2 in arguments || 0;
   var arg4 = 3 in arguments || null;

   console.log( arg1, arg2, arg3, arg4 ) 
}

Ahora, verifique algunos valores-argumento falsos para ver si su presencia se detecta correctamente y, por lo tanto, se evalúa como true :

argCheck( "", 0, false, null );
>> true true true true

Lo que significa que no fallaron en el reconocimiento de / como valores de argumento esperados. Aquí tenemos una comprobación con todos los argumentos faltantes, que según nuestro algoritmo deberían adquirir sus valores predeterminados incluso si son falsedad .

argCheck( );
>> undefined false 0 null

Como podemos ver, los argumentos arg1, arg2, arg3 y los no declarados arg4 , están devolviendo su valor predeterminado valores, según lo ordenado. Ya que ahora nos hemos asegurado de que funcione, podemos reescribir la función que realmente podrá usarlas como en el primer ejemplo usando: ya sea if o una Condición ternaria .

En las funciones que tienen más de un argumento opcional, un bucle, podría habernos ahorrado algunos bits. Pero como el argumento nombre no se inicializa si no se proporcionan sus valores, no podemos acceder a ellos por nombres, incluso si hemos escrito un valor predeterminado mediante programación, podemos solo acceda a ellos mediante argumentos [index] que la legibilidad de código inútil sea sabia.

Pero aparte de este inconveniente, que en ciertas situaciones de codificación puede ser totalmente aceptable, existe otro problema no explicado para un número múltiple y arbitrario de valores predeterminados de argumentos. Lo que puede y debe considerarse un error, ya que ya no podemos omitir argumentos, como alguna vez pudimos, sin dar un valor, en una sintaxis como:

argCheck("a",,22,{});

porque arrojará! Lo que nos hace imposible sustituir nuestro argumento con un tipo específico falsy de nuestro valor predeterminado deseado. Lo cual es estúpido, ya que el objeto de argumentos es un objeto similar a una matriz y se espera que admita esta sintaxis y convención tal como están, de forma nativa o por defecto.

Debido a esta decisión miope, ya no podemos esperar escribir una función como esta:

function argCheck( ) {
    var _default = [undefined, 0, false, null ],
        _arg = arguments;

 for( var x in _default ) {
         x in _arg ? 1 : _arg[x] = _default[x];
        }
    console.log( _arg[0],_arg[1],_arg[2],_arg[3] );
}

en cuyo caso, podríamos escribir cada valor predeterminado de un tipo deseado en la fila de argumentos y al menos acceder a ellos mediante args.index.

Por ejemplo, esta llamada a función produciría:

argCheck();
>>undefined 0 false null

como se define en nuestra matriz predeterminada de valores de argumentos. Sin embargo, lo siguiente sigue siendo posible:

argCheck({})
>>Object {  } 0 false null

argCheck({}, [])
>>Object {  } Array [  ] false null

Pero lamentablemente no:

 argCheck("a",,,22);
 >>SyntaxError: expected expression, got ','

Que de lo contrario estaría registrando:

>>a 0 false 22

pero eso está en un mundo mejor! Sin embargo, para la pregunta original, la función superior funcionará bien. por ejemplo:

function argCheck( arg, opt ) {
         1 in arguments ? 1 : opt = "default";
         console.log( arg, opt );
}

p.s .: perdón por no conservar los tipos de los valores predeterminados elegidos en las entradas de mis argumentos al escribirlos.

function foo(requiredArg){
  if(arguments.length>1) var optionalArg = arguments[1];
}
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top