有没有更好的方法来在 JavaScript 中做可选的函数参数?[复制]

Is there a better way to do optional function parameters in JavaScript? [duplicate]

提问人:Mark Biek 提问时间:9/29/2008 最后编辑:Peter MortensenMark Biek 更新时间:4/18/2020 访问量:491577

问:

我一直在 JavaScript 中处理可选参数,如下所示:

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

  // Do stuff
}

有没有更好的方法?

有没有这样的使用会失败的情况?||

JavaScript 函数 参数

评论

10赞 slf 9/29/2008
openjs.com/articles/optional_function_arguments.php
6赞 Mark Biek 9/29/2008
这很有趣。将参数作为关联数组传递似乎是处理多个参数的好方法。
1赞 Andrew Hedges 9/30/2008
在大多数情况下,这正是我所做的。具有 1 个以上参数的函数需要对象字面量。
2赞 Justus Romijn 7/20/2012
@slf我相信您的评论是受监督的,所以我在 javascript 中为 google 员工添加了一个答案。arguments
2赞 Malcolm 3/18/2016
Смотритетакже: stackoverflow.com/questions/894860/...

答:

1101赞 Paul Dixon 9/29/2008 #1

如果传递了 optionalArg,则逻辑失败,但计算结果为 false - 尝试这样做作为替代方法

if (typeof optionalArg === 'undefined') { optionalArg = 'default'; }

或者另一种成语:

optionalArg = (typeof optionalArg === 'undefined') ? 'default' : optionalArg;

使用最能传达您意图的成语!

评论

84赞 Jarrod 3/6/2012
我会使用三倍等于('...lArg === “und...') 为了安全起见。
36赞 jinglesthula 11/1/2012
最好养成使用 === 的习惯,这样你就不必记住在什么情况下它是“安全的”。
46赞 Shane N 12/20/2012
为什么在这里使用三元运算符?第二个子句不就是设置 optionalArg = optionalArg 吗?我认为只需一个简单的 IF 就可以了: if(typeof optionalArg === “undefined”) optionalArg = “defaultValue”;
14赞 Paul Dixon 2/6/2013
我认为它更好地传达了意图 - typeof 不评估操作,只检查其类型,这是我们感兴趣的。此外,评估速度将慢约 40% (jsperf.com/stackoverflow148901)
13赞 Paul Dixon 3/22/2013
好吧,您不是在谈论可选参数 - 您实际上是传递参数,因此此解决方案不适用于您的情况。NaN 并不意味着“未定义”——它意味着你已经传递了一个数字,但它的值是 NaN。有关更多信息,请参见 stackoverflow.com/questions/3215120/...
19赞 roenving 9/29/2008 #2

为此,您可以使用一些不同的方案。我一直在测试arguments.length:

function myFunc(requiredArg, optionalArg){
  optionalArg = myFunc.arguments.length<2 ? 'defaultValue' : optionalArg;

  ...

——这样做,它不可能失败,但我不知道你的方式是否有失败的机会,只是现在我想不出一个场景,它实际上会失败......

然后保罗提供了一个失败的场景!

评论

0赞 EvilSyn 9/29/2008
我很惊讶没有人提到使用参数数组!
2赞 user56reinstatemonica8 2/20/2012
什么是“一个失败的场景”?如果传递 false、null、0 等,则不会更改参数数组的长度。否则,将其与 switch(myFunc.arguments.length) 一起使用是良好且灵活的。
0赞 user56reinstatemonica8 2/20/2012
哦,我明白了 - 你的意思是 OP 中的一个失败场景,而不是你的解决方案的一个失败场景。
45赞 Oli 9/29/2008 #3

如果你需要插入一个文字,那么你可能会遇到一些问题。除此之外,不,我认为你可能走在正确的轨道上。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赞 Cris Stringfellow 3/5/2013
为什么不 hasOwnProperty 而不是 == “undefined” ?
0赞 Bart 8/14/2014
为什么不呢?为了完整起见,在这个 -statement 之前,应该检查正确的参数类型,例如 .if (!(i in argArray))ifif (typeof argArray !== "object") argArray = [];
14赞 Jonny Buchanan 9/30/2008 #4

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

这种方法有什么好处?

  • 您可以省略任意数量的参数 - 如果您只想覆盖一个参数的值,则只需提供该参数,而不必显式传递,例如有 5 个参数并且您只想自定义最后一个参数,就像您必须使用建议的其他一些方法一样。undefined
  • 当使用从另一个对象继承的构造函数时,很容易接受你所继承的对象的构造函数所需的任何参数,因为你不必在构造函数签名中命名这些参数,甚至不必提供你自己的默认值(让父对象的构造函数为你做这件事, 如上所述,当调用 的构造函数时)。CharFieldField
  • 继承层次结构中的子对象可以根据需要自定义其父构造函数的参数,强制执行自己的默认值或确保始终使用某个值。

评论

1赞 EmRa228 7/5/2012
我讨厌复杂的函数和它们的长文档。
126赞 trusktr 11/15/2011 #5

我发现这是最简单、最易读的方式:

if (typeof myVariable === 'undefined') { myVariable = 'default'; }
//use myVariable here

保罗·迪克森(Paul Dixon)的回答(以我的拙见)的可读性不如这个,但归根结底是偏好。

Insin的答案要先进得多,但对于大型函数更有用!

编辑 2013/11/17 9:33pm:我为 Node.js 创建了一个包,可以更轻松地“重载”称为参数化的函数(方法)。

评论

3赞 Jeromy French 2/6/2015
我做出了这个答案,并且被接受的答案,战斗到死。对于我运行的少数测试,接受者答案的三元方法略慢:jsperf.com/optional-function-parameters-ternary-vs-manual
33赞 user56reinstatemonica8 2/20/2012 #6

理想情况下,您可以重构以传递一个对象并将其与默认对象合并,因此传递参数的顺序无关紧要(请参阅下面本答案的第二部分)。

但是,如果您只想要快速、可靠、易于使用且体积不大的东西,请尝试以下方法:


对任意数量的默认参数进行干净的快速修复

  • 它可以优雅地扩展:每个新的默认值只需最少的额外代码
  • 您可以将其粘贴到任何位置:只需更改所需的参数和变量的数量即可
  • 如果要传递给具有默认值的参数,则该变量将设置为 。此页上的大多数其他选项将替换为默认值。undefinedundefinedundefined

下面是一个示例,用于为三个可选参数(包含两个必需参数)提供默认值

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
  }

}

简单的演示。这类似于 roenving 的答案,但可以很容易地扩展到任意数量的默认参数,更易于更新,并且使用参数而不是 Function.arguments


传递和合并对象以提高灵活性

上面的代码,就像许多做默认参数的方法一样,不能不按顺序传递参数,例如,传递但离开以回退到其默认值。optionalCoptionalB

一个不错的选择是传递对象并与默认对象合并。这也有利于可维护性(只要注意保持代码的可读性,这样未来的协作者就不会猜测你传递的对象的可能内容)。

使用 jQuery 的示例。如果您不使用 jQuery,则可以改用 Underscore 或浏览以下选项_.defaults(object, defaults)

function myFunc( args ) {
  var defaults = {
    optionalA: 'Some default',
    optionalB: 'Another default',
    optionalC: 'Some other default'
  };
  args = $.extend({}, defaults, args);
}

这是一个简单的实际示例

评论

0赞 jeromej 6/8/2014
不确定我是否理解这个。当实际给出参数时,它不会也替换值吗?!哎呀
0赞 JDC 6/19/2014
嘿,这是我见过的最干净的方式。唯一的问题是:jsperf.com/optional-parameters-typeof-vs-switch 切换显然很慢。
6赞 user56reinstatemonica8 6/20/2014
不确定我是否会称每秒 2360 万次操作很慢......的确,这非常快,但这并不意味着慢——只是没有那么快。typeofswitch
8赞 Vitim.us 5/16/2012 #7

如果您广泛使用默认值,这似乎更具可读性:

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 您可以将函数重命名为短名称,只是不要在 javascript 中使用它是保留字。defaultValuedefault

评论

0赞 Camilo Martin 9/2/2012
+1,因为我要发布我的解决方案,这是一样的:function defaultFor(arg, val) { return typeof arg !== 'undefined' ? arg : val; }
193赞 Lachlan Hunt 2/19/2013 #8

ECMAScript 2015(又名“ES6”)中,您可以在函数声明中声明默认参数值:

function myFunc(requiredArg, optionalArg = 'defaultValue') {
    // do stuff
}

有关它们的更多信息,请参阅这篇关于 MDN 的文章

目前只有 Firefox 支持此功能,但随着标准的完成,预计支持将迅速提高。


编辑 (2019-06-12):

现代浏览器现在广泛支持默认参数。
所有版本的 Internet Explorer 都不支持此功能。但是,ChromeFirefoxEdge 目前支持它。

评论

8赞 Zander Rootman 9/8/2014
这对我来说足以证明,JavaScript确实是邪恶的。@ThoAppelsin
8赞 trusktr 10/30/2015
JavaScript 只对那些不理解它的人是邪恶的(不是说你不理解,但这是我的看法)。我认为它的范式在概念上真的很强大(实现一直在变得更好)。
9赞 Hubert Grzeskowiak 7/22/2016
哦,你好 Python 语法。很高兴再次见到你。
5赞 Ilgıt Yıldırım 3/23/2017
@HubertGrzeskowiak许多其他语言也是如此,而不仅仅是 Python 或 C# :)对于默认参数值,这是相当常见的方法。
3赞 Outside_Box 6/21/2017
由于 ES6 是当前标准,因此这是正确的答案。
0赞 Brian McCutchon 2/21/2013 #9

如果我错了,请纠正我,但这似乎是最简单的方法(无论如何,对于一个论点):

function myFunction(Required,Optional)
{
    if (arguments.length<2) Optional = "Default";
    //Your code
}
-1赞 zVictor 4/12/2013 #10

我建议你这样使用 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

}

评论

0赞 vaughan 12/3/2015
不再维护。
2赞 Arman 5/7/2013 #11

我不知道为什么@Paul的回复被否决了,但反对的验证是一个不错的选择。也许一个更肯定的例子会更有意义:null

在 JavaScript 中,丢失的参数就像一个未初始化的声明变量(只是 )。相等运算符将 undefined 转换为 null,因此这适用于值类型和对象,这就是 CoffeeScript 处理可选参数的方式。var a1;

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...';
    //...
}

不过,有人担心,对于最好的语义来说,是稍微好一点。我不打算为此辩护,因为这是底层 API 如何实现函数的问题;它不应该引起 API 用户的兴趣。typeof variable === 'undefined'

我还应该补充一点,这是物理上确保遗漏任何参数的唯一方法,使用运算符,不幸的是,该运算符不适用于参数名称,因此必须传递 .inarguments

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);
2赞 slartibartfast 9/27/2013 #12

对 undefined 的测试是不必要的,并且没有那么可靠,因为正如 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

唯一不是最佳情况是,当您实际上具有应为布尔值或故意为 null 的可选参数时。

0赞 Mmmh mmh 11/8/2013 #13

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

function foo(a, b) {
    a !== undefined || (a = 'defaultA');
    if(b === undefined) b = 'defaultB';
    ...
}
1赞 NinjaFart 11/30/2013 #14

这就是我最终得到的:

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赞 Derek 朕會功夫 8/1/2014
WhoLikesCake({a: false})繁荣,您的功能不再起作用;)
6赞 Matt Montag 3/13/2014 #15

我习惯于看到处理可选变量的一些基本变化。有时,宽松的版本很有用。

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.
}

例如,与变量一起使用的虚假默认值在Backbone.js中被广泛使用。a

-2赞 Dustin Poissant 4/9/2014 #16
function foo(requiredArg){
  if(arguments.length>1) var optionalArg = arguments[1];
}

评论

2赞 Shog9 4/10/2014
您可能需要修复该错别字,并在此处添加对您推荐的内容的解释。
0赞 Dustin Poissant 4/11/2014
我认为这不需要太多解释,它只是回答了这个问题。在 JavaScript 中,有很多方法可以完成“可选函数参数”。我在这里看到了 3 或 4 个其他好的答案,但我没有看到这个答案,所以我给出了它。这可能不是最简单或最直接的答案,但它确实有效。
0赞 user56reinstatemonica8 1/2/2015
这与 Roenving 的答案相同,但没有提供默认值。也就是说,我非常喜欢将可选参数与必需参数分开定义的可读性:如果这是您回答的目的,那么这样说会有所帮助
0赞 Dustin Poissant 1/9/2015
我不认为我的答案是最好的。我更喜欢angelcool.net的答案。我只是简单地列出这是另一种选择。我永远不会使用这种方法,我只是认为提问者更愿意提出所有可用的选项,他们可以自己选择他们最喜欢的方法,我注意到这个答案没有给出,所以为了尝试为提问者提供最完整的答案,我觉得应该给出这个选项(虽然它很糟糕)。
1赞 Mark Funk 4/14/2014 #17

人-

在查看了这些解决方案和其他解决方案之后,我尝试了其中的一些解决方案,并使用最初来自 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."; 
2赞 JDC 6/19/2014 #18

我尝试了这里提到的一些选项,并对其进行了性能测试。此时此刻,逻辑器似乎是最快的。尽管这会随着时间的推移而发生变化(不同的 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>
3赞 actual_kangaroo 9/23/2014 #19

如果你使用的是下划线库(你应该这样做,这是一个很棒的库):

_.defaults(optionalArg, 'defaultValue');
1赞 user3355403 10/3/2014 #20
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/

9赞 Petr Hurtak 5/15/2015 #21

松散型检查

易于编写,但 、 、 和 将转换为默认值,这可能不是预期的结果。0''falsenullundefined

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';
}

DSW的

不幸的是,目前浏览器支持很差

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

}

评论

0赞 T.J. Crowder 8/19/2015
“检查参数变量 - 捕获所有情况,但编写起来最笨拙”在松散模式下,由于使用(这通常并不重要)可能会对性能产生负面影响。arguments
2赞 Kulbhushan Singh 10/9/2015 #22

到了这个问题,在 EcmaScript 2015 中搜索默认参数,因此只是提到......

ES6 中,我们可以执行默认参数

function doSomething(optionalParam = "defaultValue"){
    console.log(optionalParam);//not required to check for falsy values
}

doSomething(); //"defaultValue"
doSomething("myvalue"); //"myvalue"
6赞 Yann Bertrand 2/1/2016 #23

使用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
}

您也可以使用像这样 defaults 参数

function myFunc(requiredArg, { message: 'Hello', color: 'red', importance: 1 } = {}) {
  // do stuff
}

评论

1赞 jave.web 10/18/2019
将来,您将能够使用对象扩展(目前不受 Edge 支持)来编写更短的内容 - 演示小提琴:jsfiddle.net/L7evm21q 基本代码:future ref link:developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/...function test(options) { options = { someDefaultParam: '', ...options }; /* do stuff */ }
2赞 Bart Wttewaall 3/23/2016 #24

在一个项目中,我注意到我在可选参数和设置上重复了太多,所以我创建了一个类来处理类型检查并分配一个默认值,从而产生简洁易读的代码。请参阅示例,让我知道这是否适合您。

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

评论

0赞 Falk 7/14/2018
我喜欢这样,我会走类似的路。(我唯一的参数是,最多有 20 个道具的对象可能有 7 个非常重要)。实际上,它不仅是可编辑和可维护的,而且是可重用和可扩展的(例如添加回调/发出一些东西)。这很清楚,谢谢你。
1赞 Duco L 4/11/2016 #25

这是我的解决方案。有了这个,你可以留下任何你想要的参数。可选参数的顺序并不重要,您可以添加自定义验证。

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'
        });
1赞 mcfedr 5/1/2016 #26
  1. arg || 'default'是一种很好的方法,适用于 90% 的情况

  2. 当您需要传递可能是“虚假”的值时,它会失败

    • false
    • 0
    • NaN
    • ""

    对于这些情况,您需要更详细一些,并检查undefined

  3. 当你首先有可选参数时也要小心,你必须了解所有参数的类型

1赞 Pavan Varanasi 9/2/2016 #27

在 optionalArg 为 falsy 的所有情况下,您最终将得到 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 不感兴趣,但它设置了,因为它们是虚假的。

0赞 Bekim Bacaj 10/29/2016 #28

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

依靠 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 ) 
}

现在,检查一些虚假的参数值,看看它们的存在是否被正确检测到,因此计算结果为 true

argCheck( "", 0, false, null );
>> true true true true

这意味着 -他们没有未能识别/作为预期的参数值。 在这里,我们有一个检查,所有参数都缺失了,根据我们的算法,即使它们是的,也应该获得它们的默认值。

argCheck( );
>> undefined false 0 null

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

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

但是,除了这种不便(在某些编码情况下可能是完全可以接受的)之外,还有另一个无法解释的问题,即多个和任意数量的参数默认值。这可能而且应该被视为一个错误,因为我们不能再跳过参数,就像我们曾经可以在不给出值的情况下跳过参数一样,在语法中:

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

在这种情况下,我们将能够在参数行中写入所需类型的每个默认值,并且至少能够通过 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.:很抱歉在编写参数输入时没有保留所选默认值的类型

评论

0赞 Bekim Bacaj 9/8/2017
一个 JavaScript 文盲刚刚对这个问题上最好和最完整的答案投了反对票,甚至不知道为什么。也许是因为它是要阐述的,在这个过程中迷失了方向。下次祝你好运,以你的阅读和理解能力。:)
0赞 nicholaswmin 12/2/2017
投反对票的原因有很多,没有人欠你解释他们为什么这样做。不要把它看得太个人化,它是非建设性的,而且看起来很糟糕
0赞 Bekim Bacaj 12/3/2017
“许多原因”中的主要原因 - 在这种情况下 - 是一个激进的 JavaScript 无知 - 至于你不明显的错误评论,即没有人欠偶尔“愚蠢”的反对票的解释,这是不正确的 - 因为据我所知,从我第一次觉得我必须投反对票开始,SO 政策要求/指示我也为反对票做出解释。
0赞 nicholaswmin 12/3/2017
滥用大词并不能消除这样一个事实,即在你不止一个其他答案中,你得到的回答与我给你的完全相同。下次你最好把它当作建设性的批评。如果除了你之外,每个人都看起来很无知,也许你可能是无知的。
0赞 Bekim Bacaj 12/3/2017
@NicholasKyriakides建设性的批评在哪里,因为没有。投反对票不是批评——这是一种没有解释的惩罚,可能只是因为我的肤色。