8

为了用户的方便,我有一个函数,它首先接收可选参数,然后是必需的参数。例如:

ns.myFunction('optional arg', function(){
    //the required callback
});

我这样做而不是执行以下操作,因为回调正文可能很长,并且用户可能忘记覆盖可选参数的默认值:

ns.myFunction(function(){
    //the required callback
}, 'optional arg');

目前我这样做是为了检查:

function myFunction(first, second) {

    //if second is undefined and first is a function
    if (typeof second === 'undefined' && typeof first === 'function') { 
        second = first;
    }
}

问题

  • 这是正确的方法吗?
  • 我将如何做到这一点以使其扩展,特别是如果在所需参数之前有 N 个可选参数?
4

8 回答 8

4

这不是正确的方法,因为按照惯例,可选参数总是放在最后。您会看到一个原因:处理它们要容易得多。如果您关心匿名函数的长度,API 的客户端应该使用函数引用或变量:

function callback1() { //...

var callback2 = function() {//...

myFunction(callbackX, optional);

转义的问题this可以用bind().

如果你真的想走多可选参数和最后回调的路径,我可以考虑两种方法:arguments对象或将所有可选参数包装在一个options对象中。

arguments可以写:

var lastOptionalIndex = arguments.length - 2;
var callback = arguments[lastOptionalIndex + 1];  //required callback is always last
var optionalFirst = lastOptionalIndex >=0? arguments[0] : undefined;
var optionalSecond = lastOptionalIndex >=1? arguments[1] : undefined;
//...

看看它与以下相比有多丑:

function myFunction(callback, firstOptional, secondOptional //...

使用options包装器对象,您总是有两个参数:

function myFunction(options, callback);

Whereoptions只是一个对象:

{
  firstOptional: 1,
  secondOptional: 'foo'
  //...
}
于 2012-06-23T12:27:39.350 回答
2

它可以通过 ArgueJS 轻松完成

function myFunction (){
  arguments = __({first: [String], second: Function})

  // and now on, you can access your arguments by
  //   arguments.first and arguments.second
}

在ArgueJS 的第一个示例中可以找到一个非常相似的示例。注意只需要中间的参数:

function range(){ 
  arguments = __({start: [Number, 0], stop: Number, step: [Number, 1]})

  for(var i = arguments.start; i < arguments.stop; i += arguments.step)
    console.log(i);
}

回复:

>>> range(3)
 0
 1
 2
>>> range(3, 5)
 3
 4
>>> range(0, 5, 2)
 0
 2
 4
于 2013-04-12T16:32:12.817 回答
2

您可以配置函数参数,具体取决于它们的数量:

myFunction() {
    let first, second;
    if (arguments.length === 2) {
        [first, second] = arguments;
    } else if (arguments.length === 1) {
        [second] = arguments;
    }
    if ( ! first) {
        // first is undefined, so only second argument was passed.
    }
}

ES6 解构使代码干净并适合缩放。

于 2018-06-25T08:23:36.717 回答
1

没有必要命名任何参数。你可以简单地说:

if (arguments.length < 2)  // There are no optional parameters

并通过 arguments[i] 检索每个参数。该函数位于 arguments[arguments.length - 1]。

需要注意的是,typeof 运算符总是返回一个字符串,所以 == 可以用来代替 ===

于 2012-06-23T12:25:59.287 回答
1

ArgueJS:

function range(){ 
  arguments = __({start: [Number, 0], stop: Number, step: [Number, 1]});
  for(var i = arguments.start; i < arguments.stop; i += arguments.step)
    console.log(i);
}

使用 ES6 变得更漂亮:

function range(){ 
  {start, stop, step} = __({start: [Number, 0], stop: Number, step: [Number, 1]})
  for(var i = start; i < stop; i += step)
    console.log(i);
}

或 CoffeeScript:

range = ->
  {start, stop, step} = __ {start: [Number, 0], stop: Number, step: [Number, 1]}
  console.log i for i in [start...stop] by step
于 2014-10-25T17:53:41.997 回答
0

如果你真的想先传递多个可选参数,你可以这样做:

function myFunction() {
    alert("optional:");
    for(var i=0; i<arguments.length-1) alert(arguments[i]);
    alert("function: "+ arguments[arguments.length-1]);
}

但是比较丑。我认为你应该把可选的东西放在最后。

于 2012-06-23T12:28:00.153 回答
0

function test(num = 1) {
  console.log(typeof num)
}

test()           // 'number' (num is set to 1)
test(undefined)  // 'number' (num is set to 1 too)

// test with other falsy values:
test('')         // 'string' (num is set to '')
test(null)       // 'object' (num is set to null)

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Default_parameters

于 2021-03-11T06:24:03.993 回答
-1

一个简单的函数式方法:

主意:

  1. 编写一个函数 myFunction(required, optional),其中可选参数位于最后,因此很容易处理。
  2. 使用函数 appendFirstArgumentIf() 从 myFunction 创建一个新函数 myNewFunction(optional, required)。
  3. 函数 appendFirstArgumentIf 调用 myFunction,如果它通过了 testfunction,则第一个参数移动到最后一个位置,否则它不会更改参数。

_

 /**
 * @param {function} fn(a,...b)
 * @param {function} argumentTest - a function to test the first parameter
 * @return {function} returns a function that passes its first argument into 
  argumentTest. If argumentTest returns true, fn is called with the first 
  argument shifted to the last position else fn is called with the arguments 
   order unchanged
 */
function appendFirstArgumentIf (fn,argumentTest){
   return function(a,...b){
       return argumentTest(a) ? fn(...b,a) : fn(a,...b) 
   }
}

用法:

function myFunction(callback, string){
    string = string ? string : 'Default Message'
    callback(string)
}

var myNewFunction = appendFirstArgumentIf(myFunction,
                                          firstArgument=> typeof firstArgument !== 'function')


myNewFunction('New Message', console.log)  // using console.log as callback function
//>>>New Message
myNewFunction(console.log)
//>>>Default Message

也可以这样:

function mySecondFunction(callback, name, string){
string = string ? string : 'Welcome'
callback(string, name)
}

var myLatestFunction = appendFirstArgumentIf(mySecondFunction,
                                      firstArgument=> typeof firstArgument !== 'function')


myLatestFunction('Hello', console.log, 'John')
//>>>Hello John
myLatestFunction(console.log, 'John')
//>>>Welcome John
于 2019-10-10T23:14:50.650 回答