JavaScript 中的第一个可选参数

Optional argument first in JavaScript

本文关键字:参数 第一个 JavaScript      更新时间:2023-09-26

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

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 个可选参数?

这不是正确的方法,因为按照惯例,可选参数始终放在末尾。你会看到一个原因:处理它们要容易得多。如果您关心匿名函数的长度,则 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);

其中options只是一个对象:

{
  firstOptional: 1,
  secondOptional: 'foo'
  //...
}

它可以很容易地用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

您可以根据函数参数的数量配置函数参数:

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 解构使代码干净且适合扩展。

不必

命名任何参数。 你可以简单地说:

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

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

在次要说明中,typeof 运算符总是返回一个字符串,因此可以使用 == 代替 ===

争论JS:

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

或咖啡脚本:

range = ->
  {start, stop, step} = __ {start: [Number, 0], stop: Number, step: [Number, 1]}
  console.log i for i in [start...stop] by step

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

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

但它相当丑陋。我认为你应该把可选的东西放在最后。

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

一个简单的函数方法:

想法:

  1. 编写一个函数myFunction(必需,可选),其中可选参数是最后一个,因此很容易来处理。
  2. 使用函数 appendFirstArgumentIf() 从 myFunction 创建一个新函数 myNewFunction(可选,必需)。
  3. 函数 appendFirstArgumentIf 调用 myFunction,如果它传递测试函数,则第一个参数移动到最后一个位置,否则它不会更改参数。

_

 /**
 * @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