J'ai toujours géré 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?
Existe-t-il des cas où l'utilisation de ||
comme cela va échouer?
Votre logique échoue si optionalArg est passé, mais est évaluée comme false - essayez ceci comme alternative.
if (typeof optionalArg === 'undefined') { optionalArg = 'default'; }
Ou un idiome alternatif:
optionalArg = (typeof optionalArg === 'undefined') ? 'default' : optionalArg;
Utilisez le langage qui vous communique le mieux l'intention!
Dans ECMAScript 2015 ("ES6"), vous pouvez déclarer les valeurs d'argument par défaut dans la déclaration de fonction:
function myFunc(requiredArg, optionalArg = 'defaultValue') {
// do stuff
}
En savoir plus sur cet article sur MDN .
Ceci est actuellement niquement supporté par Firefox , mais comme la norme est terminée, attendez-vous à ce que le support s'améliore rapidement.
EDIT (2019-06-12):
Les paramètres par défaut sont maintenant largement pris en charge par les navigateurs modernes. Toutes les versions d'Internet Explorer ne prennent pas en charge cette fonctionnalité. Cependant, Chrome, Firefox et Edge le prennent actuellement en charge.
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 à une préférence.
la réponse de insin est beaucoup plus avancée, mais beaucoup plus utile pour les grandes fonctions!
EDIT 17/11/2013 21:33: J'ai créé un paquet pour Node.js qui facilite la "surcharge" des fonctions (méthodes) appelé paramétrique .
Si vous avez besoin d'insérer un nom littéral NULL
, vous risquez d'avoir quelques problèmes. En dehors de cela, non, je pense que vous êtes probablement sur la bonne voie.
L’autre méthode choisie par certaines personnes consiste à utiliser un tableau assoc de variables qui itère dans la liste d’arguments. Cela a l'air un peu plus ordonné mais j'imagine que c'est un peu (très peu) plus intensif en processus/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];
// ...
}
Dans l’idéal, vous refactoriez pour passer un objet et le fusionniez avec un objet par défaut. Par conséquent, l’ordre dans lequel les arguments sont passés n’a pas d’importance (voir la deuxième section de cette réponse, au dessous de).
Si, toutefois, vous voulez juste quelque chose de rapide, fiable, facile à utiliser et peu encombrant, essayez ceci:
undefined
à un argument avec une valeur par défaut, la variable est ainsi définie comme undefined
name__. La plupart des autres options de cette page remplaceraient undefined
par la valeur par défaut.Voici un exemple pour fournir des valeurs par défaut pour trois arguments optionnels (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émonstration simple . Ceci est similaire à la réponse de roenving , mais facilement extensible pour un nombre quelconque d'arguments par défaut, plus facile à mettre à jour et en utilisant arguments
not Function.arguments
.
Le code ci-dessus, à l'instar de nombreuses manières de faire des arguments par défaut, ne peut pas transmettre les arguments hors séquence, par exemple, en passant optionalC
mais en laissant optionalB
à ses valeurs par défaut.
Une bonne option pour cela consiste à transmettre des objets et à les fusionner avec un objet par défaut. Ceci est également bon pour la maintenabilité (veillez simplement à garder votre code lisible, afin que les futurs collaborateurs ne soient plus laissés au hasard quant au contenu possible des objets que vous transmettez).
Exemple utilisant jQuery. Si vous n'utilisez pas jQuery, vous pouvez également utiliser la fonction _.defaults(object, defaults)
ou de Underscore pour parcourir ces options :
function myFunc( args ) {
var defaults = {
optionalA: 'Some default',
optionalB: 'Another default',
optionalC: 'Some other default'
};
args = $.extend({}, defaults, args);
}
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, ça ne peut pas échouer, mais je ne sais pas si votre chemin a des chances d’échouer, pour le moment je ne peux pas imaginer un scénario où cela échouerait réellement ...
Et puis Paul a fourni un scénario d'échec! -)
Semblable à la réponse de Oli, j'utilise un argument Object et un objet 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 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'est-ce qui est gentil avec cette méthode?
undefined
lorsque, par exemple, il y a 5 arguments et que vous souhaitez uniquement personnaliser les paramètres. la dernière, comme vous le feriez avec certaines des autres méthodes suggérées.CharField
appelle le constructeur de Field
).Vérification de type en vrac
Facile à écrire, mais 0
, ''
, false
name__, 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';
}
Vérification de type stricte
Plus long, mais couvre la majorité des cas. Le seul cas où il attribue incorrectement la valeur par défaut est lorsque nous passons undefined
en tant que paramètre.
function myFunc(requiredArg, optionalArg) {
optionalArg = typeof optionalArg !== 'undefined' ? optionalArg : 'defaultValue';
}
Vérification de la variable des 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 de navigateur est très médiocre pour le moment.
function myFunc(requiredArg, optionalArg = 'defaultValue') {
}
Si vous utilisez beaucoup 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;
}
Il suffit de déclarer cette fonction sur l'escope global.
function defaultValue(variable,defaultValue){
return(typeof variable!=='undefined')?(variable):(defaultValue);
}
Motif d'utilisation fruit = defaultValue(fruit,'Apple');
* PS: vous pouvez renommer la fonction defaultValue
en un nom abrégé, mais n’utilisez pas default
, c’est un mot réservé en javascript.
Avec ES2015/ES6, vous pouvez tirer parti 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
}
Je suis habitué à voir quelques variations de base sur la gestion des variables optionnelles. Parfois, les versions assouplies 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 valeur par défaut utilisée avec la variable a
est, par exemple, utilisée de manière extensive dans Backbone.js .
Si vous utilisez la bibliothèque nderscore (vous devriez, c'est une bibliothèque géniale):
_.defaults(optionalArg, 'defaultValue');
Atterri à cette question, recherchant les paramètres par défaut dans EcmaScript 2015 , mentionnant donc simplement ...
Avec ES6 on peut faire paramètres par défaut :
function doSomething(optionalParam = "defaultValue"){
console.log(optionalParam);//not required to check for falsy values
}
doSomething(); //"defaultValue"
doSomething("myvalue"); //"myvalue"
Je ne sais pas pourquoi la réponse de @Paul est refusée, mais la validation par rapport à null
est un bon choix. Peut-être qu'un exemple plus affirmatif aura plus de sens:
En JavaScript, un paramètre manquant est similaire à une variable déclarée non initialisée (uniquement var a1;
). Et l'opérateur d'égalité convertit l'indéfini en null, si bien que cela fonctionne très bien 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 est à craindre que typeof variable === 'undefined'
soit légèrement meilleur pour la meilleure sémantique Je ne suis pas sur le point de défendre cela puisqu'il s'agit de l'API sous-jacente de la manière dont une fonction est implémentée; cela ne devrait pas intéresser l'utilisateur de l'API.
Je devrais également ajouter que voici le seul moyen de vérifier physiquement tout argument, en utilisant l'opérateur in
qui ne fonctionnera malheureusement pas avec les noms de paramètres. Il faut donc passer un index du 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);
J'ai essayé certaines des options mentionnées ici et les ai testées. En ce moment, le logique semble être le plus rapide. Bien que cela soit sujet à des changements dans le temps (différentes versions du moteur JavaScript).
Voici mes résultats (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
Ce test de performance peut être facilement répliqué sur: http://jsperf.com/optional-parameters-typeof-vs-switch/2
C'est le code du test:
<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>
Au cours d’un projet, j’ai remarqué que je me répétais trop avec les paramètres et paramètres facultatifs; j’ai donc créé une classe qui gère le contrôle de type et assigne une valeur par défaut, ce qui donne un code net et lisible. Voir exemple et laissez-moi savoir si cela fonctionne pour vous.
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 : [];
}
En utilisant cette classe:
(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));
Le test pour indéfini est inutile et n’est pas aussi robuste qu’il pourrait être car, comme l’a souligné l'utilisateur568458, la solution fournie échoue si la valeur null ou la valeur false est transmise. Les utilisateurs de votre API peuvent penser que false ou null forceront 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. Au lieu d'essayer:
function bulletproof(required, optionalArg){
optionalArg = optionalArg ? optionalArg : "defaultValue";;
console.log(optionalArg);
};
bulletproof("required");
bulletproof("required", "provided");
bulletproof("required", null);
bulletproof("required", false);
Ce qui résulte en:
defaultValue
provided
defaultValue
defaultValue
Le seul scénario qui ne soit pas optimal est celui où vous avez réellement des paramètres facultatifs destinés à être des booléens ou des valeurs nulles intentionnelles.
Dans tous les cas où optionalArg est faux, vous obtiendrez defaultValue.
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);
Tout le journal ci-dessus defaultValue, parce que tous les 6 sont faux. Dans les cas 4, 5 et 6, vous ne souhaiterez peut-être pas définir facultatifArg sur defaultValue, mais la valeur sera définie car elles sont fausses.
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'
});
arg || 'default'
est un excellent moyen et fonctionne dans 90% des cas
Il échoue lorsque vous devez transmettre des valeurs pouvant être "fausses".
false
name__0
NaN
name__""
Dans ces cas, vous devrez être un peu plus bavard et vérifier undefined
name__
Faites également attention lorsque vous avez d’abord des arguments optionnels, vous devez connaître les types de tous vos arguments.
Les gens -
Après avoir examiné ces solutions et d’autres, j’en ai essayé un certain nombre en utilisant comme base un extrait de code originaire de W3Schools. Vous pouvez trouver ce qui fonctionne dans ce qui suit. Chacun des éléments commentés fonctionne également et vous permet d'expérimenter simplement en supprimant des commentaires individuels. Pour être clair, c'est le paramètre "eyecolor" qui n'est pas défini.
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.";
C'est ce que j'ai fini avec:
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 ça:
WhoLikesCake({ b : "I do" });
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);
Celles-ci sont plus courtes que la version de l'opérateur typeof.
function foo(a, b) {
a !== undefined || (a = 'defaultA');
if(b === undefined) b = 'defaultB';
...
}
Corrigez-moi si je me trompe, mais cela semble être le moyen le plus simple (pour un argument, en tout cas):
function myFunction(Required,Optional)
{
if (arguments.length<2) Optional = "Default";
//Your code
}