Question Y a-t-il une meilleure façon de faire des paramètres de fonction optionnels en JavaScript? [dupliquer]


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ù l'utilisation || comme ça va échouer?


756
2017-09-29 14:27


origine


Réponses:


Votre logique échoue si optionalArg est passé, mais évalue comme false - essayez ceci comme alternative

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

Ou un idiome alternatif:

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

Utilisez n'importe quel idiome communique le mieux l'intention à vous!


1012
2017-09-29 14:30



Je trouve que c'est la manière la plus simple et la plus lisible:

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

La réponse de Paul Dixon (à mon humble avis) est moins lisible que cela, mais elle se résume à la préférence.

La réponse d'insin est beaucoup plus avancée, mais beaucoup plus utile pour les grandes fonctions!

EDIT 17/11/2013 21h33: J'ai créé un paquet pour Node.js qui rend plus facile de "surcharger" les fonctions (méthodes) appelées paramétrique.


125
2017-11-14 21:23



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 seulement supporté par Firefox, mais comme la norme est terminée, attendez-vous à ce que le soutien s'améliore rapidement.


119
2018-02-19 13:13



Si vous avez besoin de chuck littéral NULL 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];

    // ...
}

44
2017-09-29 14:34



Idéalement, vous refactoriser pour passer un objet et fusionner avec un objet par défaut, donc 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, de cette façon, la variable est définie comme undefined. La plupart des autres options sur cette page remplaceraient undefined avec 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 arguments ne pas 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 optionalCmais laissant optionalB pour 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 Underscore _.defaults(object, defaults) ou parcourir ces options:

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.


32
2018-02-20 15:36



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


17
2017-09-29 14:33



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 le souhaitez - 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 le 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'objet parent faire cela pour vous, comme vu ci-dessus quand CharField appels Fielddu constructeur).
  • 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 être utilisé.

13
2017-09-29 23:16



Si vous utilisez largement les valeurs par défaut, cela semble beaucoup plus lisible:

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

Déclarez simplement cette fonction sur l'escope global.

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

Modèle d'utilisation fruit = defaultValue(fruit,'Apple');

* PS, vous pouvez renommer le defaultValue fonction à un nom court, n'utilisez pas default c'est un mot réservé en javascript.


8
2018-05-15 21:23



Vérification de type lâche

Facile à écrire, mais 0, '', false, null et undefined sera converti 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 nous passons undefined en tant que 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') {

}

8
2018-05-15 13:46



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
}

5
2018-02-01 11:09