我总是在JavaScript中处理可选参数,如下所示:
function myFunc(requiredArg, optionalArg){
optionalArg = optionalArg || 'defaultValue';
// Do stuff
}
有更好的方法吗?
是否有任何使用||
的情况会失败?
答案 0 :(得分:1042)
如果传递了OptionalArg,您的逻辑将失败,但评估为false - 请尝试将此作为替代
if (typeof optionalArg === 'undefined') { optionalArg = 'default'; }
或另类成语:
optionalArg = (typeof optionalArg === 'undefined') ? 'default' : optionalArg;
使用哪个成语最能传达您的意图!
答案 1 :(得分:132)
在ECMAScript 2015(又名“ES6”)中,您可以在函数声明中声明默认参数值:
function myFunc(requiredArg, optionalArg = 'defaultValue') {
// do stuff
}
在this article on MDN中有关它们的更多信息(尽管有文章标题,它们在JavaScript中被称为“参数”而不是“参数”)。
目前这是only supported by Firefox,但由于标准已经完成,预计支持会迅速提升。
答案 2 :(得分:125)
我发现这是最简单,最易读的方式:
if (typeof myVariable === 'undefined') { myVariable = 'default'; }
//use myVariable here
Paul Dixon的回答(以我的拙见)不如此可读,但归结为偏好。
insin的答案要先进得多,但对大型功能更有用!
EDIT 11/17/2013 9:33 pm:我为Node.js创建了一个包,可以更容易地“重载”名为parametric的函数(方法)。< / p>
答案 3 :(得分:44)
如果您需要放入文字NULL
,那么您可能会遇到一些问题。除此之外,不,我认为你可能走在正确的轨道上。
一些人选择的另一种方法是在参数列表中迭代一组关联变量。它看起来有点整洁,但我想它有点(非常少)一点点过程/内存密集。
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];
// ...
}
答案 4 :(得分:32)
理想情况下,您将重构一个对象并使用默认对象merge传递它,因此传递参数的顺序无关紧要(请参阅下面的答案的第二部分)。
但是,如果您只想要快速,可靠,易于使用且体积不大的产品,请尝试以下方法:
undefined
传递给具有默认值的参数,这样,变量将设置为undefined
。此页面上的大多数其他选项将使用默认值替换undefined
。这是一个为三个可选参数(带有两个必需参数)提供默认值的示例
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
}
}
Simple demo。这与roenving's answer类似,但可以轻松扩展为任意数量的默认参数,更易于更新,using arguments
not Function.arguments
。
上述代码与许多执行默认参数的方法一样,不能不按顺序传递参数,例如,传递optionalC
,但让optionalB
回退到默认值。
一个很好的选择是传递对象并与默认对象合并。这也有利于可维护性(只需注意保持代码的可读性,因此未来的合作者不会猜测您传递的对象的可能内容)。
使用jQuery的示例。如果你不使用jQuery,你可以使用Underscore的_.defaults(object, defaults)
或browse these options:
function myFunc( args ) {
var defaults = {
optionalA: 'Some default',
optionalB: 'Another default',
optionalC: 'Some other default'
};
args = $.extend({}, defaults, args);
}
答案 5 :(得分:17)
您可以使用一些不同的方案。我一直在测试arguments.length:
function myFunc(requiredArg, optionalArg){
optionalArg = myFunc.arguments.length<2 ? 'defaultValue' : optionalArg;
...
- 这样做,它不可能失败,但我不知道你的方式是否有任何失败的机会,只是现在我想不出一个场景,它实际上会失败... < / p>
然后保罗提供了一个失败的场景! - )
答案 6 :(得分:13)
与Oli的答案类似,我使用一个参数Object和一个定义默认值的Object。带点糖......
/**
* 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
}
......这可以做得更好。
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)
这种方法有什么好处?
undefined
你只想自定义最后一个,就像你建议的其他一些方法一样。CharField
调用Field
的构造函数时所见)。答案 7 :(得分:8)
如果您广泛使用默认值,这似乎更具可读性:
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;
}
只需在全局escope上声明此功能。
function defaultValue(variable,defaultValue){
return(typeof variable!=='undefined')?(variable):(defaultValue);
}
使用模式fruit = defaultValue(fruit,'Apple');
* PS你可以将defaultValue
功能重命名为短名称,只是不要使用default
它是javascript中的保留字。
答案 8 :(得分:8)
宽松类型检查
易于撰写,但0
,''
,false
,null
和undefined
将转换为默认值,这可能不是预期的结果
function myFunc(requiredArg, optionalArg) {
optionalArg = optionalArg || 'defaultValue';
}
严格类型检查
更长,但涵盖了大多数情况。只有在错误地指定默认值的情况下,才会将undefined
作为参数传递。
function myFunc(requiredArg, optionalArg) {
optionalArg = typeof optionalArg !== 'undefined' ? optionalArg : 'defaultValue';
}
检查参数变量
抓住所有案件,但写起来最笨拙。
function myFunc(requiredArg, optionalArg1, optionalArg2) {
optionalArg1 = arguments.length > 1 ? optionalArg1 : 'defaultValue';
optionalArg2 = arguments.length > 2 ? optionalArg2 : 'defaultValue';
}
<强> ES6 强>
不幸的是,目前浏览器支持非常糟糕
function myFunc(requiredArg, optionalArg = 'defaultValue') {
}
答案 9 :(得分:5)
借助ES2015 / ES6,您可以利用可以取代Object.assign
或$.extend()
_.defaults()
function myFunc(requiredArg, options = {}) {
const defaults = {
message: 'Hello',
color: 'red',
importance: 1
};
const settings = Object.assign({}, defaults, options);
// do stuff
}
你也可以使用像这样的默认参数
function myFunc(requiredArg, { message: 'Hello', color: 'red', importance: 1 } = {}) {
// do stuff
}
答案 10 :(得分:4)
我习惯于看到处理可选变量的一些基本变体。有时,轻松的版本很有用。
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.
}
例如,变量a
中使用的虚假默认值在Backbone.js中广泛使用。
答案 11 :(得分:3)
如果您正在使用Underscore库(您应该,它是一个非常棒的库):
_.defaults(optionalArg, 'defaultValue');
答案 12 :(得分:2)
未定义的测试是不必要的,并且不像它可能那样健壮,因为正如user568458所指出的,如果传递null或false,则提供的解决方案将失败。您的API的用户可能会认为为false或null会强制该方法避免该参数。
function PaulDixonSolution(required, optionalArg){
optionalArg = (typeof optionalArg === "undefined") ? "defaultValue" : optionalArg;
console.log(optionalArg);
};
PaulDixonSolution("required");
PaulDixonSolution("required", "provided");
PaulDixonSolution("required", null);
PaulDixonSolution("required", false);
结果是:
defaultValue
provided
null
false
最后两个可能很糟糕。而是尝试:
function bulletproof(required, optionalArg){
optionalArg = optionalArg ? optionalArg : "defaultValue";;
console.log(optionalArg);
};
bulletproof("required");
bulletproof("required", "provided");
bulletproof("required", null);
bulletproof("required", false);
结果是:
defaultValue
provided
defaultValue
defaultValue
这不是最佳的唯一情况是当你实际上有可选的参数是布尔值或故意为空时。
答案 13 :(得分:2)
我不知道为什么@Paul的回复被低估了,但针对null
的验证是一个不错的选择。也许一个更肯定的例子会更有意义:
在JavaScript中,一个遗漏的参数就像一个未初始化的声明变量(只是var a1;
)。等于运算符将undefined转换为null,因此这对值类型和对象都很有效,这就是CoffeeScript处理可选参数的方式。
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...';
//...
}
尽管如此,有人担心最好的语义是typeof variable === 'undefined'
略好一些。我不打算为此辩护,因为底层API的问题是如何实现一个函数;它不应该对API用户感兴趣。
我还应该补充说,这是唯一一种物理确保错过任何参数的方法,使用in
运算符,遗憾的是它不能使用参数名称,因此必须传递{{1的索引}}
arguments
答案 14 :(得分:2)
我尝试了这里提到的一些选项并对它们进行了性能测试。在这一刻,逻辑似乎是最快的。虽然这是随着时间的推移而变化的主题(不同的JavaScript引擎版本)。
这些是我的结果(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
此性能测试可以轻松复制到: http://jsperf.com/optional-parameters-typeof-vs-switch/2
这是测试代码:
<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>
答案 15 :(得分:2)
登陆此问题,在EcmaScript 2015中搜索默认参数,因此只需提及......
使用 ES6 ,我们可以default parameters:
function doSomething(optionalParam = "defaultValue"){
console.log(optionalParam);//not required to check for falsy values
}
doSomething(); //"defaultValue"
doSomething("myvalue"); //"myvalue"
答案 16 :(得分:2)
在一个项目中,我注意到我使用可选参数和设置重复了太多,所以我创建了一个处理类型检查的类,并分配了一个默认值,从而产生整洁可读的代码。请参阅示例,并告诉我这是否适合您。
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 : [];
}
使用此课程:
(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));
答案 17 :(得分:1)
这就是我最终的结果:
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 ...
}
这样称呼:
WhoLikesCake({ b : "I do" });
答案 18 :(得分:1)
在OptionalArg为假的所有情况下,您最终会得到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);
以上所有日志defaultValue,因为所有6都是假的。在第4,5,6项情况下,您可能没有兴趣将optionalArg设置为defaultValue,但它设置为因为它们是假的。
答案 19 :(得分:1)
民众 -
在查看了这些和其他解决方案之后,我尝试使用最初来自W3Schools的一段代码作为基础来解决其中的一些问题。您可以找到以下内容。每个注释掉的项目都可以正常工作,这样您就可以通过删除单个注释来进行实验。需要说明的是,未定义的是“eyecolor”参数。
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.";
答案 20 :(得分:1)
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);
答案 21 :(得分:1)
arg || 'default'
是一种很棒的方式,适用于90%的案例
当您需要传递可能是&#39; falsy&#39;
的值时,它会失败false
0
NaN
""
对于这些情况,您需要更加详细并检查undefined
首先要有可选参数时要小心,你必须知道所有参数的类型
答案 22 :(得分:1)
这是我的解决方案。有了这个,你可以留下你想要的任何参数。可选参数的顺序并不重要,您可以添加自定义验证。
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'
});
答案 23 :(得分:0)
那些比运营商版本更短。
function foo(a, b) {
a !== undefined || (a = 'defaultA');
if(b === undefined) b = 'defaultB';
...
}
答案 24 :(得分:0)
如果我错了,请纠正我,但这似乎是最简单的方法(对于一个论点,无论如何):
function myFunction(Required,Optional)
{
if (arguments.length<2) Optional = "Default";
//Your code
}
答案 25 :(得分:-1)
我建议您以这种方式使用ArgueJS:
function myFunc(){
arguments = __({requiredArg: undefined, optionalArg: [undefined: 'defaultValue'})
//do stuff, using arguments.requiredArg and arguments.optionalArg
// to access your arguments
}
您还可以将undefined
替换为您希望收到的参数类型,如下所示:
function myFunc(){
arguments = __({requiredArg: Number, optionalArg: [String: 'defaultValue'})
//do stuff, using arguments.requiredArg and arguments.optionalArg
// to access your arguments
}
答案 26 :(得分:-1)
似乎最安全的方法 - 在决定使用之前处理所有 虚假类型 提供的参数 default - 用于检查调用函数中是否存在可选参数。
依赖于参数对象成员创建,如果缺少参数,它甚至不会被创建,无论它是否被声明,我们可以像这样编写你的函数:
function myFunc(requiredArg, optionalArg){
optionalArg = 1 in arguments ? optionalArg : 'defaultValue';
//do stuff
}
利用此行为: 每当我们需要确保函数在其过程中获得所需的某个值时,我们可以安全地检查参数列表中的任何缺失值。
在下面的演示代码中,我们将故意将无类型和无值 未定义 作为默认值能够确定它是否可能在虚假参数值上失败,例如0 false等,或者它是否按预期运行。
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 )
}
现在,检查几个虚假的参数值,看看它们的存在是否被正确检测,因此评估为 true :
argCheck( "", 0, false, null );
>> true true true true
这意味着 - 他们没有通过识别/作为预期的参数值而失败。 在这里,我们检查了所有缺失的参数,根据我们的算法,即使它们是 falsy ,也应该获取它们的默认值。
argCheck( );
>> undefined false 0 null
正如我们所看到的,参数 arg1,arg2,arg3 和未声明的 arg4 正在返回其确切的 默认 < / strong>值,按订购。 因为我们现在已经确定它可以正常工作,所以我们可以使用以下功能重写实际上能够使用它们的功能: if 或者三元条件。
对于具有多个可选参数的函数, - 循环,可能为我们节省了一些位。但是,如果参数 名称 在未提供其值时未初始化,即使我们以编程方式编写了默认值,我们也无法通过名称访问它们,我们可以只能通过 arguments [index] 访问它们,明智无用的代码可读性。
但除了这种不便之外,在某些编码情况下可能完全可以接受,对于多个和任意数量的参数默认值,还有另一个未解决的问题。这可能并且应该被视为一个错误,因为我们不能再跳过参数,因为我们曾经可以在不给出值的情况下使用以下语法:
argCheck("a",,22,{});
因为它会扔掉!这使得我们无法用我们所需默认值的特定 falsy 类型替换我们的参数。 这是愚蠢的,因为 arguments对象是一个类似于数组的对象,并且应该原生或默认支持这种语法和约定!
由于这个短视的决定,我们不再希望编写这样的函数:
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] );
}
在这种情况下,我们可以在参数行中写出所需类型的每个默认值,并且至少能够通过args.index访问它们。
例如,此函数调用将产生:
argCheck();
>>undefined 0 false null
在我们的默认参数值数组中定义。 但是仍然可以使用以下内容:
argCheck({})
>>Object { } 0 false null
argCheck({}, [])
>>Object { } Array [ ] false null
但遗憾的是没有:
argCheck("a",,,22);
>>SyntaxError: expected expression, got ','
否则将记录:
>>a 0 false 22
但那是一个更美好的世界! 但是 - 对于原始问题 - 最顶层的功能会很好。 e.g:
function argCheck( arg, opt ) {
1 in arguments ? 1 : opt = "default";
console.log( arg, opt );
}
p.s:抱歉在写入时我的参数输入中没有保留所选默认值的类型。
答案 27 :(得分:-2)
function foo(requiredArg){
if(arguments.length>1) var optionalArg = arguments[1];
}