有没有更好的方法在javascript中做可选的函数参数?

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

本问题已经有最佳答案,请猛点这里访问。

我总是在javascript中处理可选参数,如下所示:

1
2
3
4
5
function myFunc(requiredArg, optionalArg){
  optionalArg = optionalArg || 'defaultValue';

  // Do stuff
}

有更好的方法吗?

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


如果传递了optionalarg,但计算结果为false,则逻辑将失败-请尝试将此作为替代方法

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

或者另一个成语:

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

用最能传达你意图的成语!


在ecmascript 2015(又名"es6")中,可以在函数声明中声明默认参数值:

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

有关MDN的更多信息,请参阅本文(尽管文章标题为"arguments",而不是javascript中的"parameters")。

目前只有Firefox支持这一点,但随着标准的完成,预计支持会迅速提高。


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

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

保罗·狄克逊的回答(在我看来)比这更难理解,但归根结底还是要优先考虑。

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

edit 11/17/2013 9:33 pm:我为node.js创建了一个包,使"重载"名为参数化的函数(方法)变得更容易。


如果你需要扔掉一个字面的NULL,那么你可能会遇到一些问题。除此之外,不,我认为你可能走对了。

有些人选择的另一种方法是使用变量的assoc数组迭代参数列表。它看起来有点整洁,但我认为它有点(非常小)过程/内存密集。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
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];

    // ...
}


理想情况下,您将重构以传递一个对象并将其与默认对象合并,因此传递参数的顺序并不重要(请参见下面的第二节)。

但是,如果您只想要快速、可靠、易于使用且不笨重的东西,请尝试以下操作:

对任意数量的默认参数的快速修复

  • 它可以优雅地伸缩:为每个新默认设置最少的额外代码
  • 可以粘贴到任何地方:只需更改所需参数和变量的数量
  • 如果要将undefined传递给具有默认值的参数,则通过这种方式,变量被设置为undefined。此页面上的大多数其他选项将用默认值替换undefined

下面是一个为三个可选参数(带有两个必需参数)提供默认值的示例

1
2
3
4
5
6
7
8
9
10
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
  }

}

简单的演示。这与Roenwing的回答类似,但对于任何数量的默认参数都可以轻松扩展,更容易更新,并且使用arguments而不是Function.arguments

传递和合并对象以获得更大的灵活性

上面的代码和许多执行默认参数的方法一样,不能按顺序传递参数,例如传递optionalC,但使optionalB返回到默认状态。

一个好的选择是传递对象并与默认对象合并。这对可维护性也很好(只需注意保持代码的可读性,这样就不会让未来的合作者猜测您传递的对象的可能内容)。

使用jquery的示例。如果不使用jquery,则可以使用下划线的_.defaults(object, defaults)或浏览这些选项:

1
2
3
4
5
6
7
8
function myFunc( args ) {
  var defaults = {
    optionalA: 'Some default',
    optionalB: 'Another default',
    optionalC: 'Some other default'
  };
  args = $.extend({}, defaults, args);
}

下面是一个简单的实例。


你可以用一些不同的方案来解决这个问题。我一直在测试参数。长度:

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

  ...

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

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


与oli的答案类似,我使用参数对象和定义默认值的对象。加一点糖…

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
/**
 * 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
}

…这可以做得更好一点。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
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,您只需要定制最后一个参数,就像您必须使用其他一些建议的方法一样。
  • 当为从另一个继承的对象使用构造函数函数时,很容易接受您所继承的对象的构造函数所需的任何参数,因为您不必在构造函数签名中命名这些参数,甚至不必提供自己的默认值(让父对象的构造函数这样做是为了如上图所示,当CharField调用Field的构造函数时。
  • 继承层次结构中的子对象可以根据需要自定义其父构造函数的参数,强制使用自己的默认值,或者确保始终使用某个值。


如果您广泛使用缺省值,那么这看起来更易读:

1
2
3
4
5
6
7
8
9
10
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上声明此函数。

1
2
3
function defaultValue(variable,defaultValue){
    return(typeof variable!=='undefined')?(variable):(defaultValue);
}

使用模式fruit = defaultValue(fruit,'Apple');

*ps您可以将defaultValue函数重命名为短名称,只是不要使用default,它是javascript中的保留字。


松动式检查

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

1
2
3
function myFunc(requiredArg, optionalArg) {
    optionalArg = optionalArg || 'defaultValue';
}

严格的类型检查

更长,但涵盖了大多数案例。它错误地分配默认值的唯一情况是当我们将undefined作为参数传递时。

1
2
3
function myFunc(requiredArg, optionalArg) {
    optionalArg = typeof optionalArg !== 'undefined' ? optionalArg : 'defaultValue';
}

检查参数变量

抓住所有的案例,但写起来最笨拙。

1
2
3
4
function myFunc(requiredArg, optionalArg1, optionalArg2) {
    optionalArg1 = arguments.length > 1 ? optionalArg1 : 'defaultValue';
    optionalArg2 = arguments.length > 2 ? optionalArg2 : 'defaultValue';
}

ES6

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

1
2
3
function myFunc(requiredArg, optionalArg = 'defaultValue') {

}


使用ES2015/ES6,您可以利用Object.assign,它可以取代$.extend()_.defaults()

1
2
3
4
5
6
7
8
9
10
11
function myFunc(requiredArg, options = {}) {
  const defaults = {
    message: 'Hello',
    color: 'red',
    importance: 1
  };

  const settings = Object.assign({}, defaults, options);

  // do stuff
}

您也可以使用这样的默认参数

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

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

1
2
3
4
5
6
7
8
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一起使用的falsy默认值在主干.js中广泛使用。


如果您使用的是下划线库(您应该使用,它是一个很棒的库):

1
_.defaults(optionalArg, 'defaultValue');

对于未定义的测试是不必要的,并且不如它可能的那么健壮,因为正如用户568458指出的那样,如果通过了null或false,所提供的解决方案将失败。您的API用户可能认为false或null会强制该方法避免使用该参数。

1
2
3
4
5
6
7
8
function PaulDixonSolution(required, optionalArg){
   optionalArg = (typeof optionalArg ==="undefined") ?"defaultValue" : optionalArg;
   console.log(optionalArg);
};
PaulDixonSolution("required");
PaulDixonSolution("required","provided");
PaulDixonSolution("required", null);
PaulDixonSolution("required", false);

结果是:

1
2
3
4
defaultValue
provided
null
false

最后两个可能是坏的。相反,尝试:

1
2
3
4
5
6
7
8
function bulletproof(required, optionalArg){
   optionalArg = optionalArg ? optionalArg :"defaultValue";;
   console.log(optionalArg);
};
bulletproof("required");
bulletproof("required","provided");
bulletproof("required", null);
bulletproof("required", false);

结果是:

1
2
3
4
defaultValue
provided
defaultValue
defaultValue

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


我尝试了这里提到的一些选项,并对它们进行了性能测试。此时,Logicalor似乎是最快的。尽管这是随时间变化的主题(不同的javascript引擎版本)。

以下是我的结果(Microsoft Edge 20.10240.16384.0):

1
2
3
4
5
6
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://jspef.com/optional-parameters-typeof-vs-switch/2

这是测试代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js">

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


找到这个问题,在ecmascript 2015中搜索默认参数,因此只提到…

使用ES6,我们可以执行默认参数:

1
2
3
4
5
6
function doSomething(optionalParam ="defaultValue"){
    console.log(optionalParam);//not required to check for falsy values
}

doSomething(); //"defaultValue"
doSomething("myvalue"); //"myvalue"

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

在javascript中,缺少的参数类似于未初始化的已声明变量(仅限于var a1;)。相等运算符将未定义的转换为空,因此这对值类型和对象都很有用,这就是coffeescript处理可选参数的方式。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
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的索引。

1
2
3
4
5
6
7
8
9
10
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);

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
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 : [];
}

使用此类:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
(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));


这就是我最后得出的结论:

1
2
3
4
5
6
7
8
9
10
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 ...
}

这样称呼:

1
WhoLikesCake({ b :"I do" });


乡亲们

在研究了这些解决方案和其他解决方案之后,我尝试了其中的一些方法,使用一段最初来自W3Schools的代码作为基础。您可以在下面找到工作原理。每一个被注释掉的项目也可以工作,这样你就可以简单地通过删除单个注释来进行实验。很明显,它是未定义的"eyecolor"参数。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
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
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
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 +"
"
+ test2 +"
"
+ test3 +"
"
+ test4);

http://jsfiddle.net/mq60hqrf/


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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
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'
        });

  • arg || 'default'是一种很好的方法,适用于90%的病例。

  • 当你需要传递可能是"不稳定"的值时,它会失败。

    • false
    • 0
    • NaN
    • ""

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

  • 另外,当您首先有可选参数时要小心,您必须知道所有参数的类型。


  • 在所有情况下,如果optionalarg是错误的,您将以defaultvalue结束。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    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);

    以上所有的日志默认值,因为6个都是错误的。在案例4、5、6中,您可能不想将optionalarg设置为defaultvalue,但它会设置,因为它们是错误的。


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

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


    那些比类型的操作员版本短。

    1
    2
    3
    4
    5
    function foo(a, b) {
        a !== undefined || (a = 'defaultA');
        if(b === undefined) b = 'defaultB';
        ...
    }

    我建议你这样使用arguejs:

    1
    2
    3
    4
    5
    6
    7
    function myFunc(){
      arguments = __({requiredArg: undefined, optionalArg: [undefined: 'defaultValue'})

      //do stuff, using arguments.requiredArg and arguments.optionalArg
      //    to access your arguments

    }

    您还可以将undefined替换为您希望接收的参数类型,如下所示:

    1
    2
    3
    4
    5
    6
    7
    function myFunc(){
      arguments = __({requiredArg: Number, optionalArg: [String: 'defaultValue'})

      //do stuff, using arguments.requiredArg and arguments.optionalArg
      //    to access your arguments

    }


    似乎在决定使用默认值之前,最安全的方法是检查被调用函数中是否存在可选参数,以处理所有提供的参数类型的错误。

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

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

    利用这种行为:我们可以在需要确保函数在其过程中获得所需的某个值时,任意和显式地检查参数列表中是否有任何缺少的值。

    在下面的演示代码中,我们故意将一个无类型和无值未定义的值作为默认值,以便能够确定它是否可能在错误的参数值(如0 false等)上失败,或者它的行为是否如预期的那样。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    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 )
    }

    现在,检查一些错误的参数值,以查看是否正确检测到它们的存在,因此评估为真:

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

    也就是说,它们并没有不符合预期的参数值。这里我们检查所有缺少的参数,根据我们的算法,这些参数应该获得它们的默认值,即使它们是错误的。

    1
    2
    argCheck( );
    >> undefined false 0 null

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

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

    但是除了在某些编码情况下完全可以接受的这种不便之外,对于多个和任意数量的参数默认值还有另一个未计算的问题。这可能也应该被视为一个bug,因为我们不能再跳过参数,因为我们曾经可以在不给出值的情况下,使用如下语法:

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

    因为它会扔!这使得我们不可能用我们想要的默认值的特定错误类型来替换我们的参数。这是愚蠢的,因为arguments对象是一个类似数组的对象,并且应该支持这种语法和约定,无论是本地的还是默认的!

    由于这个短视的决定,我们不能再希望编写这样的函数:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    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访问这些值。

    例如,此函数调用将生成:

    1
    2
    argCheck();
    >>undefined 0 false null

    在默认的参数值数组中定义。但是,以下仍然是可能的:

    1
    2
    3
    4
    5
    argCheck({})
    >>Object {  } 0 false null

    argCheck({}, [])
    >>Object {  } Array [  ] false null

    但遗憾的是:

    1
    2
     argCheck("a",,,22);
     >>SyntaxError: expected expression, got ','

    否则将记录:

    1
    >>a 0 false 22

    但那是一个更好的世界!不过,对于最初的问题,最上面的函数也可以。例如。:

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

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


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