JavaScript中有更好的可选函数参数的方式吗?

863

我一直是这样处理 JavaScript 中的可选参数:

function myFunc(requiredArg, optionalArg){
  optionalArg = optionalArg || 'defaultValue';

  // Do stuff
}

有没有更好的方法?

在什么情况下使用像||这样的方式会失败?


10
http://www.openjs.com/articles/optional_function_arguments.php - slf
6
很有意思。将参数作为关联数组传递似乎是处理超过几个参数的好方法。 - Mark Biek
1
这正是我在大多数情况下所做的。我的具有超过1个参数的函数期望一个对象字面量。 - Andrew Hedges
2
@slf 我相信你的评论被忽略了,所以我为那些在谷歌上搜索的人添加了一个关于JavaScript中arguments的答案。 - Justus Romijn
2
参见:https://dev59.com/WXNA5IYBdhLWcg3wmfO5 - Malcolm
显示剩余2条评论
28个回答

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."; 

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

2
"WhoLikesCake({a: false})" 砰的一声,你的函数不再工作 ;) - Derek 朕會功夫

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

http://jsfiddle.net/mq60hqrf/


0

看起来最安全的方法 - 在决定使用默认值之前,处理所有\任何提供的虚假类型参数 - 是检查调用函数中可选参数的存在\出现。

依赖于参数对象成员创建,如果缺少参数,则不会创建该成员,而不管它是否声明,我们可以像这样编写您的函数:

  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

这意味着-它们没有未能识别/作为预期参数值。 在这里,我们检查了所有参数都缺失的情况,根据我们的算法,即使它们是虚假的,也应该获取它们的默认值。
argCheck( );
>> undefined false 0 null

正如我们所看到的,参数arg1、arg2、arg3和未声明的arg4都按照顺序返回它们的确切默认值。因为我们现在已经确保它可以工作,我们可以重写函数,实际上能够像第一个示例那样使用它们,方法是使用:if三元条件。

对于具有多个可选参数的函数,-循环可能会节省一些位。但由于如果没有提供值,参数名称不会被初始化,因此我们无法再通过名称访问它们,即使我们已经以编程方式编写了默认值,我们只能通过arguments[index]访问它们,这在代码可读性方面是无用的。

但除了这种不便之外,在某些编码情况下可能完全可以接受,还存在另一个未经考虑的问题,即多个和任意数量的参数默认值。这可能并且应该被视为错误,因为我们不能再跳过参数,就像我们曾经能够做的那样,在语法中不给出值,例如:

argCheck("a",,22,{});

因为它会抛出异常!这使我们无法使用特定的 falsy 类型来替换我们所需的默认值参数。

这很愚蠢,因为arguments object是一个类似数组的对象,并且期望本地或默认支持此语法和约定!

由于这个短视的决定,我们再也无法编写像这样的函数:

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

但那只存在于一个更美好的世界! 然而 - 对于原始问题 - 最上层的函数就可以了。 例如:

function argCheck( arg, opt ) {
         1 in arguments ? 1 : opt = "default";
         console.log( arg, opt );
}

p.s.:抱歉在编写参数输入时没有保留所选默认值的类型


一个 JavaScript 文盲刚刚在不知道原因的情况下,对这个问题中最好、最完整的答案进行了负评。也许是因为它太复杂了,在过程中迷失了方向。祝你下次阅读和理解能力更好。 :) - Bekim Bacaj
有很多理由可以给你的帖子点踩,但没有人欠你一个解释为什么要这样做。不要太在意,这是非建设性的,也会让人看起来不好。 - nicholaswmin
“许多原因”中的主要原因是对JavaScript的激进无知。关于您不明显的错误评论,即没有人需要解释偶尔的“愚蠢”投票,这是不正确的,因为我记得从第一次我感到需要投反对票时,SO政策要求/指示我也必须给出反对票的解释。” - Bekim Bacaj
@NicholasKyriakides,你有建设性的批评吗?因为我没有看到。下投票并不是批评,它只是一种未经解释的惩罚,而且可能只是因为我的肤色问题。 - Bekim Bacaj
可能仅仅是因为我的肤色,我几乎可以保证社区并不是那样的。当你要求评论负面投票时更友善一些,有人会给你的,这就是我想说的全部。 - nicholaswmin
显示剩余2条评论

0

这些比 typeof 运算符版本更短。

function foo(a, b) {
    a !== undefined || (a = 'defaultA');
    if(b === undefined) b = 'defaultB';
    ...
}

0

如果我错了,请纠正我,但这似乎是最简单的方法(至少对于一个参数):

function myFunction(Required,Optional)
{
    if (arguments.length<2) Optional = "Default";
    //Your code
}

-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

}

不再维护。 - vaughan

-2
function foo(requiredArg){
  if(arguments.length>1) var optionalArg = arguments[1];
}

2
你可能想要修复那个错别字,并为你在这里推荐的内容添加一个解释。 - Shog9
我认为这不需要太多的解释,它只是回答了问题。在JavaScript中,有许多实现“可选函数参数”的方法。我在这里看到了3或4个其他好的答案,但我没有看到这个答案,所以我给出了它。它可能不是最简单或最直接的答案,但它确实有效。 - Dustin Poissant
这与Roenving的答案相同,但不提供默认值。话虽如此,我非常喜欢将可选参数单独定义为必需参数的可读性:如果您的回答的目的是这样,那么说明一下会有所帮助。 - user56reinstatemonica8
我并不认为我的答案是最好的。我更喜欢angelcool.net的答案。我只是列出这是另一个选项。我永远不会使用这种方法,我只是认为提问者可能更喜欢所有可用的选项,并且他们可以自己选择哪种方法最好,我注意到这个答案没有被给出,所以为了尽力提供最完整的答案,我觉得应该给出这个选项(虽然它很糟糕)。 - Dustin Poissant

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接