【问题标题】:Is there a better way to do optional function parameters in JavaScript? [duplicate]有没有更好的方法在 JavaScript 中执行可选函数参数? [复制]
【发布时间】:2010-09-14 00:23:23
【问题描述】:

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

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

  // Do stuff
}

有没有更好的方法?

在任何情况下使用|| 会失败吗?

【问题讨论】:

标签: javascript function arguments


【解决方案1】:

如果 optionalArg 被传递,您的逻辑将失败,但评估结果为 false - 试试这个作为替代方法

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

或其他成语:

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

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

【讨论】:

  • 为了安全起见,我会使用三重等号 ('...lArg === "und...')。
  • 最好养成使用 === 的习惯,这样您就不必记住在哪些情况下它是“安全的”。
  • 为什么在这里使用三元运算符?第二个子句不只是设置 optionalArg = optionalArg 吗?我认为只是一个简单的 IF 就可以了: if(typeof optionalArg === "undefined") optionalArg = "defaultValue";
  • 我认为它更好地表明了意图 - typeof 不评估操作,只检查它的类型,这是我们感兴趣的。此外,评估会慢 40% 左右(@987654321 @)
  • 好吧,你不是在谈论可选参数 - 你真的正在传递一个参数,所以这个解决方案不适用于你的情况。 NaN 并不意味着“未定义”——它意味着你传递了一个数字,但它的值是 NaN。更多信息请参见stackoverflow.com/questions/3215120/…
【解决方案2】:

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

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

this article on MDN了解更多信息。

目前是only supported by Firefox,但随着标准的完成,预计支持会迅速改善。


编辑(2019-06-12):

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

【讨论】:

  • 这足以证明 JavaScript 确实是邪恶的。 @ThoAppelsin
  • JavaScript 只对那些不理解它的人是邪恶的(不是说你不理解,但这是我的看法)。我认为它的范式在概念上真的很强大(实现一直在变得更好)。
  • 哦,你好 Python 语法。很高兴再次见到你。
  • @HubertGrzeskowiak 对于许多其他语言同样适用,而不仅仅是 Python 或 C# :) 默认参数值是相当常见的方法。
  • 由于 ES6 是当前标准,这是正确的答案。
【解决方案3】:

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

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

Paul Dixon 的回答(以我的拙见)比这更难读,但归结为偏好。

insin 的答案更高级,但对大型功能更有用!

编辑 2013 年 11 月 17 日晚上 9:33: 我为 Node.js 创建了一个包,它可以更轻松地“重载”名为 parametric 的函数(方法)。

【讨论】:

  • +1,但 typeof 返回一个字符串,因此您需要在 undefined 周围加上引号才能使其工作:if(typeof myVariable == "undefined")...
  • 我做出了这个答案,并且接受了答案,战斗至死。对于我运行的少数测试,接受者答案的三元方法稍慢:jsperf.com/optional-function-parameters-ternary-vs-manual
  • @OmShankar 不会有任何区别的。
【解决方案4】:

如果您需要输入文字 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];

    // ...
}

【讨论】:

  • 为什么不用 hasOwnProperty 而不是 == "undefined" ?
  • 为什么不改用if (!(i in argArray))?为了完整起见,在此if-statement 之前,应该检查正确的参数类型,例如if (typeof argArray !== "object") argArray = [];.
【解决方案5】:

理想情况下,您可以重构以传递一个对象,并使用默认对象 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);
}

这里是a simple example of it in action

【讨论】:

  • 不确定我是否理解这一点。当实际给出参数时,它不会也替换值吗?!哦
  • 嘿,这是我见过的最干净的方式。唯一的问题是:jsperf.com/optional-parameters-typeof-vs-switch 开关显然很慢..
  • 不确定我是否会称每秒 2360 万次操作很慢...确实typeof 非常快,但这并不会使 switch 慢 - 只是没有那么快。
【解决方案6】:

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

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

  ...

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

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

【讨论】:

  • 我很惊讶没有人提到使用参数数组!
  • 什么是“一个失败的场景”?如果您传递 false、null、0 等,则不会更改参数数组的长度。否则,将其与 switch(myFunc.arguments.length) 一起使用既好又灵活。
  • 哦,我明白了 - 你的意思是 OP 中的一个失败场景,而不是你的解决方案中的一个失败场景。
【解决方案7】:

与 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 个参数并且您只想自定义最后一个,因为您必须使用建议的其他一些方法。
  • 当使用从另一个继承的对象的构造函数函数时,很容易接受您要继承的对象的构造函数所需的任何参数,因为您不必在您的构造函数签名,甚至提供您自己的默认值(让父 Object 的构造函数为您执行此操作,如上所示 CharField 调用 Field 的构造函数时)。
  • 继承层次结构中的子对象可以根据需要为其父构造函数自定义参数,强制执行自己的默认值或确保始终使用某个值。

【讨论】:

  • 我讨厌复杂的函数和冗长的文档。
【解决方案8】:

松散类型检查

容易编写,但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';
}

ES6

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

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

}

【讨论】:

  • “检查参数变量 - 捕获所有情况,但写起来最笨拙” 由于使用 arguments,在松散模式下可能会对性能产生负面影响(不是这样通常很重要)。
【解决方案9】:

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

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 中的保留字。

【讨论】:

  • +1 因为我要发布我的解决方案,这是一样的:function defaultFor(arg, val) { return typeof arg !== 'undefined' ? arg : val; }
【解决方案10】:

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

【讨论】:

  • 将来,您将能够通过对象传播(Edge 目前不支持!)编写更短的代码 - 演示小提琴:jsfiddle.net/L7evm21q 基本代码:function test(options) { options = { someDefaultParam: '', ...options }; /* do stuff */ } 未来参考链接:@987654322 @
【解决方案11】:

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

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 中广泛使用。

【讨论】:

    【解决方案12】:

    如果您使用Underscore 库(您应该使用它,这是一个很棒的库):

    _.defaults(optionalArg, 'defaultValue');
    

    【讨论】:

      【解决方案13】:

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

      使用 ES6 我们可以做到default parameters:

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

      【讨论】:

        【解决方案14】:

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

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

        【讨论】:

        • 我喜欢这样,我会采取类似的方式。 (我唯一的参数是最多 20 个道具的对象可能是 7 个非常重要)。实际上它不仅是可重用和可维护的,它也是可重用和可扩展的(例如添加回调/发出某些东西)。很清楚,谢谢。
        【解决方案15】:

        我不知道为什么@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 运算符,不幸的是它不适用于参数名称,因此必须传递 arguments 的索引。

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

        【讨论】:

          【解决方案16】:

          对 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
          

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

          【讨论】:

            【解决方案17】:

            我尝试了此处提到的一些选项并对其进行了性能测试。此时逻辑或似乎是最快的。尽管这是随时间变化的主题(不同的 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>
            

            【讨论】:

              【解决方案18】:

              这就是我最终的结果:

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

              【讨论】:

              • WhoLikesCake({a: false})繁荣你的功能不再工作;)
              【解决方案19】:

              伙计们-

              在查看了这些解决方案和其他解决方案之后,我使用最初来自 W3Schools 的 sn-p 代码作为基础尝试了其中的一些解决方案。您可以在下面找到有效的方法。注释掉的每个项目也都有效,并且可以让您通过删除单个 cmets 来进行实验。需要明确的是,没有定义的是“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】:
                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/

                【讨论】:

                  【解决方案21】:

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

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

                  【讨论】:

                    【解决方案22】:
                    1. arg || 'default' 是一种很好的方法,适用于 90% 的情况

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

                      • false
                      • 0
                      • NaN
                      • ""

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

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

                    【讨论】:

                      【解决方案23】:

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

                      上面所有的log都是defaultValue,因为6个都是falsy。在第 4、5、6 种情况下,您可能对将 optionalArg 设置为 defaultValue 不感兴趣,但由于它们是虚假的,因此它会设置。

                      【讨论】:

                        【解决方案24】:

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

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

                        【讨论】:

                          【解决方案25】:

                          那些比 typeof 运算符版本短。

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

                          【讨论】:

                            【解决方案26】:

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

                            【讨论】:

                            • 不再维护。
                            【解决方案27】:

                            似乎最安全的方法 - 在决定使用 default - 检查被调用函数中是否存在可选参数

                            依赖于参数对象成员的创建,如果参数丢失,它甚至不会被创建,不管它可能被声明,我们可以这样编写你的函数:

                              function myFunc(requiredArg, optionalArg){
                                    optionalArg = 1 in arguments ? optionalArg : 'defaultValue';
                              //do stuff
                              }
                            

                            利用这种行为: 当我们需要确保函数获得其过程中所需的某个值时,我们可以安全地任意明确地检查参数列表中的任何缺失值。

                            在下面的演示代码中,我们会特意把一个typelessvaluelessundefined作为默认值能够确定它是否可能在错误的参数值(例如 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 正在返回它们的确切 默认值 值,按顺序排列。 因为我们现在已经确保它可以工作,所以我们可以重写函数,它实际上可以像第一个示例中那样使用它们,方法是:if三元条件。

                            对于具有多个可选参数的函数,- 循环,可能会为我们节省一些代码。但是由于参数 names 如果没有提供它们的值就不会被初始化,即使我们以编程方式编写了默认值,我们也不能再通过名称访问它们,我们可以只能通过 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
                            

                            但那是一个更好的世界! 但是 - 对于原始问题 - 最顶层的功能就可以了。 例如:

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

                            p.s.:很抱歉在编写它们时没有在我的参数输入中保留所选默认值的 types

                            【讨论】:

                            • 一个 JavaScript 文盲刚刚对这个问题的最佳和最完整的答案投了反对票,甚至不知道为什么。也许是因为它是精心制作的,在这个过程中迷失了方向。下次祝你好运,你的阅读和理解能力。 :)
                            • 投反对票的原因有很多,没有人欠你解释他们为什么这样做。不要把它看得太私人,它没有建设性而且看起来很糟糕
                            • “许多原因”的主要原因 - 在这种情况下 - 是一个激进的 JavaScript 无知 - 至于你不明显的错误言论,即没有人对偶尔的“愚蠢”投票做出解释,是不正确 - 因为据我记得从我第一次觉得我不得不投反对票时,SO 政策要求/指示我也对投反对票做出解释。
                            • 滥用大词并不能消除这样一个事实,即在您的多个其他答案中,您得到的答案与我给您的完全相同。下次你最好把它当作建设性的批评。如果除了你之外,每个人看起来都很无知,那么可能是你自己才是无知的人。
                            • @NicholasKyriakides 哪里是建设性的批评,因为没有。否决票不是批评——这是没有解释的惩罚,可能仅仅是因为我的肤色。
                            【解决方案28】:
                            function foo(requiredArg){
                              if(arguments.length>1) var optionalArg = arguments[1];
                            }
                            

                            【讨论】:

                            • 您可能需要更正该错字并在此处为您推荐的内容添加说明。
                            • 我认为这不需要太多解释,它只是回答了问题。在 JavaScript 中实现“可选函数参数”的方法有很多种。我在这里看到了 3 或 4 个其他好的答案,但我没有看到这个答案,所以我给了。这可能不是最简单或最直接的答案,但确实有效。
                            • 这与 Roenving 的答案相同,但不提供默认值。也就是说,我非常喜欢将可选参数与必需参数分开定义的可读性:如果这是您回答的目的,那么这样说会有所帮助
                            • 我不认为我的答案是最好的。我更喜欢 angelcool.net 的回答。我只是列出这是另一种选择。我永远不会使用这种方法,我只是认为提问者更愿意提出所有可用的选项,他们可以自己选择他们最喜欢的方法,我注意到没有给出这个答案,所以为了尝试提供有最完整答案的提问者我觉得应该给出这个选项(虽然它很烂)。
                            猜你喜欢
                            • 2011-12-08
                            • 1970-01-01
                            • 1970-01-01
                            • 1970-01-01
                            • 1970-01-01
                            • 2021-04-02
                            • 2012-07-06
                            • 2011-11-17
                            • 2013-08-12
                            相关资源
                            最近更新 更多