Ich habe immer optionale Parameter in JavaScript wie folgt behandelt:
function myFunc(requiredArg, optionalArg){
optionalArg = optionalArg || 'defaultValue';
// Do stuff
}
Gibt es einen besseren Weg, dies zu tun?
Gibt es Fälle, in denen die Verwendung von ||
fehlschlägt?
Ihre Logik schlägt fehl, wenn optionalArg übergeben wird, wird jedoch als falsch bewertet. Versuchen Sie dies als Alternative
if (typeof optionalArg === 'undefined') { optionalArg = 'default'; }
Oder eine alternative Sprache:
optionalArg = (typeof optionalArg === 'undefined') ? 'default' : optionalArg;
Verwenden Sie die Sprache, die Ihnen die Absicht am besten vermittelt!
In ECMAScript 2015 (auch bekannt als "ES6") können Sie Standardargumentwerte in der Funktionsdeklaration deklarieren:
function myFunc(requiredArg, optionalArg = 'defaultValue') {
// do stuff
}
Mehr darüber in dieser Artikel auf MDN .
Dies ist derzeit nur von Firefox unterstützt , aber da der Standard fertiggestellt wurde, sollte sich die Unterstützung schnell verbessern.
EDIT (2019-06-12):
Standardparameter werden heute von modernen Browsern weitgehend unterstützt. Alle Versionen von Internet Explorer unterstützen diese Funktion nicht. Derzeit wird es jedoch von Chrome, Firefox und Edge unterstützt.
Ich halte dies für die einfachste und am besten lesbare Methode:
if (typeof myVariable === 'undefined') { myVariable = 'default'; }
//use myVariable here
Paul Dixons Antwort (meiner bescheidenen Meinung nach) ist weniger lesbar als diese, aber es kommt auf die Präferenz an.
die Antwort von insin ist viel weiter fortgeschritten, aber viel nützlicher für große Funktionen!
EDIT 17.11.2013 21:33: Ich habe ein Paket für Node.js erstellt, das das "Überladen" von Funktionen (Methoden) erleichtert. genannt parametrisch .
Wenn Sie ein wörtliches NULL
eingeben müssen, können einige Probleme auftreten. Abgesehen davon, nein, ich denke, Sie sind wahrscheinlich auf dem richtigen Weg.
Die andere Methode, die manche Leute wählen, ist die Verwendung eines Assoc-Arrays von Variablen, die die Argumentliste durchlaufen. Es sieht ein bisschen ordentlicher aus, aber ich stelle mir vor, es ist ein bisschen (sehr wenig) prozess-/speicherintensiver.
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];
// ...
}
Im Idealfall würden Sie ein Objekt überarbeiten und mit einem Standardobjekt zusammenführen , sodass die Reihenfolge, in der die Argumente übergeben werden, keine Rolle spielt (siehe den zweiten Abschnitt dieser Antwort). unten).
Wenn Sie jedoch nur etwas schnelles, zuverlässiges, benutzerfreundliches und nicht sperriges möchten, versuchen Sie Folgendes:
undefined
an ein Argument mit einem Standardwert übergeben möchten, wird die Variable auf diese Weise als undefined
festgelegt. Die meisten anderen Optionen auf dieser Seite ersetzen undefined
durch den Standardwert.Hier ist ein Beispiel für die Angabe von Standardwerten für drei optionale Argumente (mit zwei erforderlichen Argumenten).
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
}
}
Einfache Demo . Dies ähnelt der Antwort von roenving , ist jedoch für eine beliebige Anzahl von Standardargumenten leicht erweiterbar, einfacher zu aktualisieren und mit arguments
not Function.arguments
.
Der obige Code kann wie viele andere Arten der Ausführung von Standardargumenten keine Argumente außerhalb der Reihenfolge übergeben, z. B. optionalC
übergeben, optionalB
jedoch auf den Standardwert zurücksetzen.
Eine gute Option dafür ist, Objekte zu übergeben und mit einem Standardobjekt zusammenzuführen. Dies ist auch gut für die Wartbarkeit (achten Sie nur darauf, dass Ihr Code lesbar bleibt, damit zukünftige Mitarbeiter nicht über den möglichen Inhalt der Objekte nachdenken müssen, die Sie weitergeben).
Beispiel mit jQuery. Wenn Sie jQuery nicht verwenden, können Sie stattdessen Unterstrichs _.defaults(object, defaults)
oder verwenden und diese Optionen durchsuchen :
function myFunc( args ) {
var defaults = {
optionalA: 'Some default',
optionalB: 'Another default',
optionalC: 'Some other default'
};
args = $.extend({}, defaults, args);
}
Hier ist ein einfaches Beispiel dafür in Aktion .
Sie können dafür verschiedene Schemata verwenden. Ich habe immer auf arguments.length getestet:
function myFunc(requiredArg, optionalArg){
optionalArg = myFunc.arguments.length<2 ? 'defaultValue' : optionalArg;
...
Dabei kann es unmöglich scheitern, aber ich weiß nicht, ob Ihr Weg scheitern könnte. Ich kann mir gerade kein Szenario ausdenken, in dem es tatsächlich scheitern würde.
Und dann hat Paul ein scheiterndes Szenario geliefert! -)
Ähnlich wie bei Olis Antwort verwende ich ein Argument Object und ein Object, das die Standardwerte definiert. Mit ein bisschen Zucker ...
/**
* 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
}
... das kann ein bisschen schöner gemacht werden.
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)
Was ist schön an dieser Methode?
undefined
übergeben zu müssen, wenn beispielsweise 5 Argumente vorhanden sind und Sie nur möchte die letzte anpassen, wie Sie es mit einigen der anderen vorgeschlagenen Methoden tun müssten.CharField
den Konstruktor von Field
aufruft).Lose Typprüfung
Leicht zu schreiben, aber 0
, ''
, false
, null
und undefined
werden in den Standardwert konvertiert, der möglicherweise nicht zum erwarteten Ergebnis führt.
function myFunc(requiredArg, optionalArg) {
optionalArg = optionalArg || 'defaultValue';
}
Strenge Typprüfung
Länger, deckt aber die meisten Fälle ab. Der einzige Fall, in dem der Standardwert falsch zugewiesen wird, ist, wenn undefined
als Parameter übergeben wird.
function myFunc(requiredArg, optionalArg) {
optionalArg = typeof optionalArg !== 'undefined' ? optionalArg : 'defaultValue';
}
Überprüfung der Argumente Variable
Fängt alle Fälle ab, ist aber am schwersten zu schreiben.
function myFunc(requiredArg, optionalArg1, optionalArg2) {
optionalArg1 = arguments.length > 1 ? optionalArg1 : 'defaultValue';
optionalArg2 = arguments.length > 2 ? optionalArg2 : 'defaultValue';
}
ES6
Leider hat dies im Moment sehr schlechte Browserunterstützung
function myFunc(requiredArg, optionalArg = 'defaultValue') {
}
Wenn Sie die Standardeinstellungen häufig verwenden, ist dies besser lesbar:
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;
}
Deklarieren Sie diese Funktion einfach im globalen Escope.
function defaultValue(variable,defaultValue){
return(typeof variable!=='undefined')?(variable):(defaultValue);
}
Verwendungsmuster fruit = defaultValue(fruit,'Apple');
* PS Sie können die Funktion defaultValue
in einen Kurznamen umbenennen. Verwenden Sie einfach nicht default
, es ist ein reserviertes Wort in Javascript.
Mit ES2015/ES6 können Sie Object.assign
nutzen, das $.extend()
oder _.defaults()
ersetzen kann.
function myFunc(requiredArg, options = {}) {
const defaults = {
message: 'Hello',
color: 'red',
importance: 1
};
const settings = Object.assign({}, defaults, options);
// do stuff
}
Sie können auch Standardargumente wie dieses verwenden
function myFunc(requiredArg, { message: 'Hello', color: 'red', importance: 1 } = {}) {
// do stuff
}
Ich bin es gewohnt, ein paar grundlegende Variationen im Umgang mit optionalen Variablen zu sehen. Manchmal sind die entspannten Versionen nützlich.
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.
}
Die mit der Variablen a
verwendete falsche Standardeinstellung wird beispielsweise häufig in Backbone.js verwendet.
Wenn Sie die nterstrich Bibliothek verwenden (Sie sollten, es ist eine großartige Bibliothek):
_.defaults(optionalArg, 'defaultValue');
Ich bin auf diese Frage gestoßen und habe in EcmaScript 2015 nach Standardparametern gesucht , um nur zu erwähnen ...
Mit ES6 können wir Standardparameter :
function doSomething(optionalParam = "defaultValue"){
console.log(optionalParam);//not required to check for falsy values
}
doSomething(); //"defaultValue"
doSomething("myvalue"); //"myvalue"
Ich weiß nicht, warum @ Pauls Antwort abgelehnt wird, aber die Validierung gegen null
ist eine gute Wahl. Vielleicht ergibt ein positiveres Beispiel einen besseren Sinn:
In JavaScript ist ein fehlender Parameter wie eine deklarierte Variable, die nicht initialisiert wird (nur var a1;
). Und der Gleichheitsoperator konvertiert das Undefinierte in Null, sodass dies sowohl bei Werttypen als auch bei Objekten hervorragend funktioniert. Auf diese Weise behandelt CoffeeScript optionale Parameter.
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...';
//...
}
Es gibt jedoch Bedenken, dass für die beste Semantik typeof variable === 'undefined'
etwas besser ist. Ich werde dies nicht verteidigen, da es an der zugrunde liegenden API liegt, wie eine Funktion implementiert wird. es sollte den API-Benutzer nicht interessieren.
Ich sollte auch hinzufügen, dass dies die einzige Möglichkeit ist, physisch sicherzustellen, dass ein Argument übersehen wurde, indem der Operator in
verwendet wird, der mit den Parameternamen leider nicht funktioniert. Daher muss ein Index des Operators arguments
übergeben werden.
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);
Ich habe einige der hier genannten Optionen ausprobiert und die Leistung getestet. In diesem Moment scheint der Logiker der schnellste zu sein. Dies kann sich jedoch im Laufe der Zeit ändern (verschiedene Versionen der JavaScript-Engine).
Dies sind meine Ergebnisse (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
Dieser Leistungstest kann leicht wiederholt werden auf: http://jsperf.com/optional-parameters-typeof-vs-switch/2
Dies ist der Code des Tests:
<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>
Während eines Projekts bemerkte ich, dass ich mich zu oft mit den optionalen Parametern und Einstellungen wiederholte. Daher erstellte ich eine Klasse, die die Typprüfung behandelt und einen Standardwert zuweist, der zu sauberem und lesbarem Code führt. Sehen Sie sich das Beispiel an und lassen Sie mich wissen, ob dies für Sie funktioniert.
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 : [];
}
Mit dieser Klasse:
(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));
Der Test für undefined ist unnötig und nicht so robust wie er sein könnte, da, wie user568458 betont hat, die bereitgestellte Lösung fehlschlägt, wenn null oder false übergeben wird. Benutzer Ihrer API denken möglicherweise, dass false oder null die Methode zwingen würden, diesen Parameter zu vermeiden.
function PaulDixonSolution(required, optionalArg){
optionalArg = (typeof optionalArg === "undefined") ? "defaultValue" : optionalArg;
console.log(optionalArg);
};
PaulDixonSolution("required");
PaulDixonSolution("required", "provided");
PaulDixonSolution("required", null);
PaulDixonSolution("required", false);
Das Ergebnis ist:
defaultValue
provided
null
false
Die letzten beiden sind möglicherweise schlecht. Versuchen Sie stattdessen Folgendes:
function bulletproof(required, optionalArg){
optionalArg = optionalArg ? optionalArg : "defaultValue";;
console.log(optionalArg);
};
bulletproof("required");
bulletproof("required", "provided");
bulletproof("required", null);
bulletproof("required", false);
Was in ... endet:
defaultValue
provided
defaultValue
defaultValue
Das einzige Szenario, in dem dies nicht optimal ist, besteht darin, dass Sie optionale Parameter haben, die Boolesche Werte oder absichtliche Nullwerte sein sollen.
In allen Fällen, in denen optionalArg falsch ist, erhalten Sie 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);
Alle obigen log defaultValue, da alle 6 falsch sind. In den Fällen 4, 5 und 6 könnten Sie nicht daran interessiert sein, optionalArg als defaultValue festzulegen, dies wird jedoch festgelegt, da sie falsch sind.
Hier ist meine Lösung. Hiermit können Sie einen beliebigen Parameter belassen. Die Reihenfolge der optionalen Parameter ist nicht wichtig, und Sie können eine benutzerdefinierte Validierung hinzufügen.
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'
ist ein großartiger Weg und funktioniert in 90% der Fälle
Es schlägt fehl, wenn Sie Werte übergeben müssen, die möglicherweise 'falsch' sind.
false
0
NaN
""
In diesen Fällen müssen Sie etwas ausführlicher sein und prüfen, ob undefined
Seien Sie auch vorsichtig, wenn Sie zuerst optionale Argumente haben. Sie müssen die Typen aller Ihrer Argumente kennen
Leute -
Nachdem ich mir diese und andere Lösungen angesehen hatte, probierte ich einige davon mit einem Codeausschnitt aus W3Schools als Basis aus. Im Folgenden finden Sie, was funktioniert. Jedes der auskommentierten Elemente funktioniert auch und ermöglicht es Ihnen, einfach zu experimentieren, indem Sie einzelne Kommentare entfernen. Klar ist, dass der Parameter "Augenfarbe" nicht definiert wird.
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.";
Dies ist, was ich am Ende mit:
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 ...
}
So genannt:
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);
Diese sind kürzer als die Operator-Version.
function foo(a, b) {
a !== undefined || (a = 'defaultA');
if(b === undefined) b = 'defaultB';
...
}
Korrigieren Sie mich, wenn ich falsch liege, aber dies scheint der einfachste Weg zu sein (jedenfalls für ein Argument):
function myFunction(Required,Optional)
{
if (arguments.length<2) Optional = "Default";
//Your code
}