JavaScript:函数中的可选第一个参数

69

我有一个带有一些参数的典型Javascript函数。

my_function = function(content, options) { action }

如果我这样调用函数:

my_function (options)

参数"options"被传递为"content"

我该如何解决这个问题,以便可以同时传递两个参数或只传递一个参数? 谢谢

13个回答

101

您需要决定将一个单一参数作为哪个参数来处理。您不能同时将其视为contentoptions

我看到两种可能性:

  1. 更改参数顺序,即function(options, content)
  2. 检查是否定义了options

    function(content, options) {
        if(typeof options === "undefined") {
            options = content;
            content = null;
        }
        //action
    }
    

    但是你必须正确地记录文档,如果只向函数传递一个参数会发生什么,因为仅从函数签名中无法立即明确此事。


1
undefined是一个全局属性,具有恒定的值,因此您不需要引用它。在过时的浏览器中,您可能会意外地将其设置为任意值,但这不是现代浏览器的情况。 - andreszs
5
@Andrew:typeof 总是返回一个字符串。另外,if (options === undefined) 也可以起作用。但正如你所说,旧版浏览器中可能会覆盖 undefined,因此仍然普遍的做法是不直接使用 undefined(除非你在某个地方明确定义了)。 - Felix Kling
1
不要使用===来比较字符串,即使它们具有相同的内容,也不一定是同一个对象。 - inetphantom
2
@inetphantom:不确定你在说什么。那没有意义。原始字符串根本不是对象。 - Felix Kling
如果您知道contentoptions的类型不同,可以检查content的类型并进行交换。我也看到有人计算参数来实现这一点。检查content而不是options还提供了一些额外的参数验证。 - DKebler

30
my_function = function(hash) { /* use hash.options and hash.content */ };

然后调用:

my_function ({ options: options });
my_function ({ options: options, content: content });

@Muneer:这只是一个例子。 - Sarfraz
43
红宝石背景的确准迹象。 - FrontierPsycho
3
或Perl。 - Marnen Laibow-Koser
2
@BlueBird哈希只是指哈希表(又称字典/关联数组),Darin将其等同于JavaScript对象。 - icc97

22

像这样:

my_function (null, options) // for options only
my_function (content) // for content only
my_function (content, options) // for both

16

With ES6:

function test(a, b = 3) {
   console.log(a, b);
}

test(1);      // Output: 1 3
test(1, 2);   // Output: 1 2


5

你也可以根据获取的内容类型进行区分。选项曾经是一个对象,而内容则是一个字符串,因此您可以这样说:

if ( typeof content === "object" ) {
  options = content;
  content = null;
}

或者,如果您对重命名感到困惑,您可以使用参数数组,这样会更加直接:
if ( arguments.length === 1 ) {
  options = arguments[0];
  content = null;
}

1
我更喜欢这种变体:var optional_arg = arguments.length >= 1 ? arguments[0] : '默认值'; - Richard Davies

3

关于ES6中的默认参数有一篇很不错的文章,你可以在MDN网站上查看。在ES6中,现在可以进行如下操作:

secondDefaultValue = 'indirectSecondDefaultValue';

function MyObject( param1 = 'firstDefaultValue', param2 = secondDefaultValue ){
    this.first = param1;
    this.second = param2;
}

您还可以按照以下方式使用:
var object = new MyObject( undefined, options );

这将为第一个param1设置默认值'firstDefaultValue',并将您的options用于第二个param2

在这里查看演示


2
我为处理JavaScript函数的可选参数创建了一个简单的库,详见https://github.com/ovatto/argShim。该库是以Node.js为基础开发的,但应该很容易移植到例如浏览器中运行。
示例:
var argShim = require('argShim');
var defaultOptions = {
  myOption: 123
};

var my_function = argShim([
    {optional:'String'},
    {optional:'Object',default:defaultOptions}
  ], function(content, options) {
    console.log("content:", content, "options:", options);
  });

my_function();
my_function('str');
my_function({myOption:42});
my_function('str', {myOption:42});

输出:

content: undefined options: { myOption: 123 }
content: str options: { myOption: 123 }
content: undefined options: { myOption: 42 }
content: str options: { myOption: 42 }

主要针对的是模块接口,需要能够处理导出模块函数的不同调用。

这段代码非常冗长,并且使用了“default”这个在 JS 中已经是关键字的单词。不建议使用。 - Domino
虽然可能有些冗长,但它确实提供了一些简单参数存在检查之外的附加功能。在每个函数中编写相同的功能肯定会更加冗长。此外,尽管有些人不喜欢,但在ES5中保留关键字可以自由地用作属性名称。不过整个库编写得比较仓促,所以你(和我)的体验可能会有所不同 :) - ovatto

2
有两种方法可以实现这个目标。
1)
function something(options) {
    var timeToLive = options.timeToLive || 200; // default to 200 if not set
    ...
}

2)

function something(timeToDie /*, timeToLive*/) {
    var timeToLive = arguments[1] || 200; // default to 200 if not set
    ..
}

在1)中,options是一个JS对象,其中包含所需的任何属性。这样更易于维护和扩展。
在2)中,函数签名清晰易读,并且可以理解第二个参数是可选的。我曾在Mozilla的代码和文档中看到过这种风格的使用。

1

只是为了再次强调一下,因为我不得不在两个或多个必需参数中间实现一个可选参数。使用arguments数组,并将最后一个用作必需的非可选参数。

my_function() {
  var options = arguments[argument.length - 1];
  var content = arguments.length > 1 ? arguments[0] : null;
}

1
你可以将所有可选参数作为第一个参数的对象传递。第二个参数是回调函数。现在,你可以在第一个参数对象中接受任意数量的参数,并将其设置为可选项,如下所示:
function my_func(op, cb) {
    var options = (typeof arguments[0] !== "function")? arguments[0] : {},
        callback = (typeof arguments[0] !== "function")? arguments[1] : arguments[0];

    console.log(options);
    console.log(callback);
}

如果您在调用时没有传递选项参数,它将默认为空对象:
my_func(function () {});
=> options: {}
=> callback: function() {}

如果您使用选项参数调用它,您将获得所有参数:
my_func({param1: 'param1', param2: 'param2'}, function () {});
=> options: {param1: "param1", param2: "param2"}
=> callback: function() {}

这显然可以进行调整以适应两个以上的参数,但会变得更加混乱。如果您可以只使用对象作为第一个参数,则可以使用该对象传递无限数量的参数。如果您绝对需要更多可选参数(例如my_func(arg1,arg2,arg3,...,arg10,fn)),那么我建议使用像ArgueJS这样的库。我个人没有使用过它,但它看起来很有前途。

非常感谢...这正是我在寻找的。我的函数有6个参数,其中一些参数具有默认值。但是有些参数应该在函数调用中设置。我认为这个答案很适合我的情况。再次感谢... :) - CJ Ramki

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