我一直在处理JavaScript中的可选参数,如下所示:
function myFunc(requiredArg, optionalArg){
optionalArg = optionalArg || 'defaultValue';
// Do stuff
}
有更好的方法吗?
这样使用||会失败吗?
我一直在处理JavaScript中的可选参数,如下所示:
function myFunc(requiredArg, optionalArg){
optionalArg = optionalArg || 'defaultValue';
// Do stuff
}
有更好的方法吗?
这样使用||会失败吗?
当前回答
乡亲们-
在研究了这些和其他解决方案之后,我使用最初来自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.";
其他回答
与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。例如,如果有5个参数,并且您只想自定义最后一个参数,则必须使用其他建议的方法。当为从另一个继承的对象使用构造函数Function时,很容易接受所继承对象的构造函数所需的任何参数,因为您不必在构造函数签名中命名这些参数,或者甚至提供自己的默认值(让父对象的构造函数为您实现,正如上面CharField调用Field的构造函数时所看到的那样)。继承层次结构中的子对象可以根据需要为其父构造函数自定义参数,强制使用自己的默认值或确保始终使用某个值。
我不知道为什么@Paul的回复被否决,但对null的验证是一个不错的选择。也许一个更肯定的例子会更有意义:
在JavaScript中,缺少的参数就像未初始化的声明变量(仅vara1;)。相等运算符将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运算符,不幸的是,它无法处理参数名称,因此必须传递参数索引。
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);
似乎最安全的方法-在决定使用默认值之前处理所有提供的错误类型的参数-是检查所调用函数中是否存在可选参数。
依赖于arguments对象成员创建(如果缺少参数,甚至不会创建),无论它可能被声明,我们都可以这样编写函数:
function myFunc(requiredArg, optionalArg){
optionalArg = 1 in arguments ? optionalArg : 'defaultValue';
//do stuff
}
利用此行为:每当我们需要确保函数获得其过程中所需的某个值时,我们都可以安全地检查参数列表中的任何缺失值。
在下面的演示代码中,我们将故意将一个无类型和无值的undefined作为默认值,以便能够确定它是否会在错误的参数值(如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 )
}
现在,检查几个错误的参数值,看看是否正确检测到它们的存在,并因此计算为真:
argCheck( "", 0, false, null );
>> true true true true
这意味着-它们没有将/识别为预期的参数值。这里我们检查了所有参数的缺失,根据我们的算法,即使它们是假的,也应该获取它们的默认值。
argCheck( );
>> undefined false 0 null
如我们所见,参数arg1、arg2、arg3和未声明的arg4按顺序返回其确切的默认值。因为我们现在已经确定了它的有效性,所以我们可以重写函数,该函数实际上可以像第一个示例中那样使用它们,方法是使用if或三元条件。
对于具有多个可选参数的函数,-循环,可能会为我们节省一些时间。但是,由于如果不提供参数名称的值,则参数名称不会被初始化,因此即使我们以编程方式编写了默认值,我们也无法再通过名称访问它们,因此只能通过参数[索引]访问它们,这对代码的可读性来说是无用的。
但除了在某些编码情况下可能完全可以接受的这种不便之外,还有一个未知的问题,即多个任意数量的参数默认值。这可能也应该被认为是一个错误,因为我们不能再跳过参数,因为我们曾经可以在不提供值的情况下,使用如下语法:
argCheck("a",,22,{});
因为它会扔!这使得我们无法用所需默认值的特定错误类型替换参数。这是愚蠢的,因为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] );
}
在这种情况下,我们将能够在arguments行中写入所需类型的每个默认值,并且至少能够通过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
但那是一个更好的世界!然而,对于最初的问题,最上面的函数会做得很好。例如。:
function argCheck( arg, opt ) {
1 in arguments ? 1 : opt = "default";
console.log( arg, opt );
}
p.s.:很抱歉,在编写参数输入时没有保留所选默认值的类型。
如果需要插入一个NULL,那么可能会遇到一些问题。除此之外,不,我认为你可能走上了正确的轨道。
有些人选择的另一种方法是使用一个变量的assoc数组在参数列表中迭代。它看起来有点整洁,但我想它有点(非常少)更需要处理/内存。
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];
// ...
}
如果我错了,请纠正我,但这似乎是最简单的方法(无论如何,对于一个论点):
function myFunction(Required,Optional)
{
if (arguments.length<2) Optional = "Default";
//Your code
}