for - fonction onclick javascript




Y a-t-il une meilleure façon de faire des paramètres de fonction optionnels en JavaScript? (20)

  1. arg || 'default' arg || 'default' est un bon moyen et fonctionne pour 90% des cas

  2. Il échoue lorsque vous devez transmettre des valeurs qui pourraient être «fausses»

    • false
    • 0
    • NaN
    • ""

    Pour ces cas, vous devrez être un peu plus bavard et vérifier pour undefined

  3. Soyez prudent lorsque vous avez d'abord des arguments optionnels, vous devez être conscient des types de tous vos arguments

Cette question a déjà une réponse ici:

J'ai toujours traité les paramètres optionnels en JavaScript comme ceci:

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

  // Do stuff
}

Y a-t-il une meilleure façon de le faire?

Y a-t-il des cas où utiliser || comme ça va échouer?


Atteint à cette question, recherche des paramètres par défaut dans EcmaScript 2015 , mentionnant ainsi juste ...

Avec ES6 nous pouvons faire les paramètres par défaut :

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

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

Avec ES2015 / ES6 vous pouvez profiter de Object.assign qui peut remplacer $.extend() ou _.defaults()

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

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

  // do stuff
}

Vous pouvez également utiliser des arguments par défaut comme celui-ci

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

C'est ce que j'ai fini par:

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

Appelé comme ceci:

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

Corrigez-moi si je me trompe, mais cela semble être le moyen le plus simple (pour un argument, de toute façon):

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

Dans ECMAScript 2015 (alias "ES6"), vous pouvez déclarer les valeurs d'argument par défaut dans la déclaration de la fonction:

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

Plus à leur sujet dans cet article sur MDN (malgré le titre de l'article, ils sont appelés "arguments", pas "paramètres", en JavaScript).

Ceci est actuellement uniquement pris en charge par Firefox , mais une fois la norme terminée, attendez-vous à une amélioration rapide du support.


Idéalement, vous refactoriser pour passer un objet et le merge avec un objet par défaut, de sorte que l'ordre dans lequel les arguments sont passés n'a pas d'importance (voir la deuxième section de cette réponse, ci-dessous).

Si, cependant, vous voulez juste quelque chose de rapide, fiable, facile à utiliser et pas encombrant, essayez ceci:

Un correctif rapide pour tout nombre d'arguments par défaut

  • Il évolue avec élégance: un minimum de code supplémentaire pour chaque nouvelle valeur par défaut
  • Vous pouvez le coller n'importe où: changez simplement le nombre d'args et de variables requis
  • Si vous voulez passer undefined à un argument avec une valeur par défaut, la variable est définie comme undefined . La plupart des autres options de cette page remplaceront undefined par la valeur par défaut.

Voici un exemple pour fournir des valeurs par défaut pour trois arguments facultatifs (avec deux arguments obligatoires)

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
  }

}

Démo simple . Ceci est similaire à la réponse de Roenving , mais facilement extensible pour n'importe quel nombre d'arguments par défaut, plus facile à mettre à jour, et en utilisant des arguments non Function.arguments .

Passer et fusionner des objets pour plus de flexibilité

Le code ci-dessus, comme de nombreuses façons de faire des arguments par défaut, ne peut pas passer les arguments hors de la séquence, par exemple en passant optionalC mais en laissant optionalB revenir à sa valeur par défaut.

Une bonne option pour cela est de passer des objets et de fusionner avec un objet par défaut. C'est également bon pour la maintenabilité (prenez soin de garder votre code lisible, afin que les futurs collaborateurs ne puissent pas deviner le contenu possible des objets que vous passez).

Exemple utilisant jQuery. Si vous n'utilisez pas jQuery, vous pouvez utiliser les _.defaults(object, defaults) de _.defaults(object, defaults) ou merge :

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

Voici un exemple simple en action .


Il semble que le moyen le plus sûr - traiter tous les types d' arguments fournis avant de décider d'utiliser la valeur par défaut - est de vérifier l'existence de l' argument optionnel dans la fonction invoquée.

S'appuyant sur la création d'un membre de l'objet arguments qui n'est même pas créé si l'argument est manquant, indépendamment du fait qu'il pourrait être déclaré, nous pouvons écrire votre fonction comme ceci:

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

Utilisation de ce comportement: Nous pouvons vérifier en toute sécurité les valeurs manquantes dans la liste des arguments arbitrairement et explicitement chaque fois que nous devons nous assurer que la fonction obtient une certaine valeur requise dans sa procédure.

Dans le code de démonstration suivant, nous allons délibérément mettre une valeur indéfinie sans valeur et sans valeur pour pouvoir déterminer si elle peut échouer sur des valeurs d'arguments falsifiées, telles que 0 false etc., ou si elle se comporte comme prévu.

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

Maintenant, en vérifiant quelques arguments-valeurs falsy pour voir si leur présence est correctement détectée et donc évalue à vrai :

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

Ce qui signifie qu'ils n'ont pas échoué à la reconnaissance de / comme valeurs d'argument attendues. Ici nous avons un contrôle avec tous les arguments manquants, qui selon notre algo devraient acquérir leurs valeurs par défaut même s'ils sont faux .

argCheck( );
>> undefined false 0 null

Comme nous pouvons le voir, les arguments arg1, arg2, arg3 et le non déclaré arg4 , retournent leurs valeurs par défaut exactes, comme ordonné. Parce que nous avons maintenant fait en sorte que cela fonctionne, nous pouvons réécrire la fonction qui sera réellement en mesure de les utiliser comme dans le premier exemple en utilisant: if ou une condition ternaire .

Pour les fonctions qui ont plus d'un argument optionnel, une boucle peut nous avoir sauvé quelques bits. But since argument names don't get initialized if their values are not supplied, we cannot access them by names anymore even if we've programmatically written a default value, we can only access them by arguments[index] which useless code readability wise.

But aside from this inconvenience, which in certain coding situations might be fully acceptable, there's another unaccounted problem for multiple and arbitrary number of argument defaults. Which may and should be considered a bug, as we can no longer skip arguments, as we once might have been able to, without giving a value, in a syntax such as:

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

because it will throw! Which makes it impossible for us to substitute our argument with a specific falsy type of our desired default value. Which is stupid, since the arguments object is an array-like object and is expected to support this syntax and convention as is, natively or by default!

Because of this shortsighted decision we can no longer hope to write a function like this:

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

in which case, we would be able to write each default value of a desired type in arguments row and be able to at least access them by args.index.

For instance this function call would yield:

argCheck();
>>undefined 0 false null

as defined in our default array of arguments values. However the following is still possible:

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

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

But regretfully not:

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

Which would otherwise be logging:

>>a 0 false 22

but that's in a better world! However - for the original question - the topmost function will do just fine. eg:

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

ps: sorry for not preserving the types of chosen defaults in my argument inputs while writing them.


J'ai l'habitude de voir quelques variations de base sur la gestion des variables optionnelles. Parfois, les versions détendues sont utiles.

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

La falsification par défaut utilisée avec la variable a est, par exemple, largement utilisée dans Backbone.js .


Je ne sais pas pourquoi la réponse de @ Paul est downvoted, mais la validation contre null est un bon choix. Peut-être qu'un exemple plus affirmatif aura plus de sens:

En JavaScript, un paramètre manqué est comme une variable déclarée qui n'est pas initialisée (juste var a1; ). Et l'opérateur d'égalité convertit le non défini en null, ce qui fonctionne parfaitement avec les types de valeur et les objets, et c'est ainsi que CoffeeScript gère les paramètres facultatifs.

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...';
    //...
}

Cependant, il y a des soucis que pour la meilleure sémantique est typeof variable === 'undefined' est légèrement meilleur. Je ne suis pas sur le point de le défendre puisque c'est la question de l'API sous-jacente comment une fonction est implémentée; cela ne devrait pas intéresser l'utilisateur de l'API.

Je devrais également ajouter que voici la seule façon de s'assurer physiquement qu'un argument quelconque a été manqué, en utilisant l'opérateur in qui, malheureusement, ne fonctionnera pas avec les noms de paramètres, donc il faut passer un index des arguments .

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

Je vous suggère d'utiliser ArgueJS cette façon:

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

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

}

Vous pouvez également remplacer undefined par le type de l'argument que vous souhaitez recevoir, comme ceci:

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

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

}

Le test pour undefined est inutile et n'est pas aussi robuste qu'il pourrait l'être car, comme l'a signalé user568458, la solution fournie échoue si null ou false est passé. Les utilisateurs de votre API peuvent penser que false ou null forcerait la méthode à éviter ce paramètre.

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

Le résultat est:

defaultValue
provided
null
false

Ces deux derniers sont potentiellement mauvais. Essayez plutôt:

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

Ce qui entraîne:

defaultValue
provided
defaultValue
defaultValue

Le seul scénario où ce n'est pas optimal est quand vous avez réellement des paramètres facultatifs qui sont censés être booléens ou null intentionnels.


Si vous avez besoin d'un NULL littéral dans, alors vous pourriez avoir quelques problèmes. À part ça, non, je pense que vous êtes probablement sur la bonne voie.

L'autre méthode que certains choisissent consiste à prendre un assoc de variables en itérant dans la liste des arguments. Il semble un peu plus soigné mais j'imagine que c'est un peu (très peu) un peu plus de processus / de mémoire.

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

    // ...
}

Si vous utilisez la bibliothèque Underscore (vous devriez, c'est une bibliothèque géniale):

_.defaults(optionalArg, 'defaultValue');

Similaire à la réponse d'Oli, j'utilise un argument Object et un Object qui définit les valeurs par défaut. Avec un peu de sucre ...

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

... cela peut être rendu un peu plus agréable.

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'y a-t-il de bien dans cette méthode?

  • Vous pouvez omettre autant d'arguments que vous voulez - si vous voulez seulement remplacer la valeur d'un argument, vous pouvez simplement fournir cet argument, au lieu d'avoir à passer explicitement undefined quand, disons qu'il y a 5 arguments et que vous voulez seulement personnaliser dernier, comme vous auriez à faire avec certaines des autres méthodes suggérées.
  • Lorsque vous travaillez avec une fonction constructeur pour un objet qui en hérite, il est facile d'accepter tous les arguments requis par le constructeur de l'objet dont vous héritez, car vous n'avez pas besoin de nommer ces arguments dans votre signature constructeur. ou même fournir vos propres valeurs par défaut (laissez le constructeur de l'Object parent faire cela pour vous, comme vu ci-dessus quand CharField appelle le constructeur de Field ).
  • Les objets enfants dans les hiérarchies d'héritage peuvent personnaliser les arguments de leur constructeur parent comme ils le souhaitent, en appliquant leurs propres valeurs par défaut ou en s'assurant qu'une certaine valeur sera toujours utilisée.

Voici ma solution. Avec cela, vous pouvez laisser n'importe quel paramètre que vous voulez. L'ordre des paramètres facultatifs n'est pas important et vous pouvez ajouter une validation personnalisée.

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

Vous pouvez utiliser différents schémas pour cela. J'ai toujours testé pour arguments.length:

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

  ...

- Ce faisant, il ne peut pas échouer, mais je ne sais pas si votre chemin a une chance d'échouer, mais maintenant je ne peux pas imaginer un scénario, où il échouerait réellement ...

Et puis Paul a fourni un scénario qui échoue! -)


Vérification de type lâche

Facile à écrire, mais 0 , '' , false , null et undefined seront convertis en valeur par défaut, ce qui pourrait ne pas être le résultat attendu.

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

Strict contrôle de type

Plus long, mais couvre la majorité des cas. Seul le cas où il affecte incorrectement la valeur par défaut est quand on passe undefined en paramètre.

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

Vérification de la variable d'arguments

Attrape tous les cas mais est le plus maladroit à écrire.

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

ES6

Malheureusement, le support des navigateurs est très médiocre en ce moment

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

}

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/


function foo(requiredArg){
  if(arguments.length>1) var optionalArg = arguments[1];
}




arguments