【问题标题】:Allow either named arguments or positional arguments in Javascript在 Javascript 中允许命名参数或位置参数
【发布时间】:2015-12-17 06:17:43
【问题描述】:

如何让函数接受 任一 命名参数 (foo({a: 'hello', b: 'it is me'})) 位置参数 (foo('hello', 'it is me'))?

我知道可以通过将对象传递给函数来模拟命名参数:

function foo(options) {
    options = options || {};
    var a = options.a || 'peanut'; // whatever default value
    var b = options.b || 'butter'; // whatever default value
    console.log(a, b);
}

// ES6 allows automatic destructuring
function foo({a = 'peanut', b = 'butter'} = {}) {
    console.log(a, b);
}

但这不允许我接受要传递的位置参数。

我想使用 ES6,但 ES5 中的任何东西也可以。

【问题讨论】:

  • 您可以检测出两种场景之间的差异,但前提是您了解预期的参数类型并可以对其进行测试以查看传递给函数的场景。
  • @jfriend00 想过检查第一个参数是否是一个对象,以确定是否使用了命名参数,但是如果我也需要 a 作为一个对象怎么办。这会混淆这两种情况。有什么想法吗?
  • 用于检测不同变量传递方案的 JavaScript 技术取决于参数的类型和数量。你必须设计一个方案,让你区分不同的可能性。您可以查看How to Overload Functions in Javascript 来详细讨论这些可能性。
  • 糖太多了。用显式输入编写好的函数。仅仅因为某种特定语言可能实现某些事情并不意味着您应该这样做。

标签: javascript parameter-passing ecmascript-6


【解决方案1】:

首先,我真的建议坚持使用一种方法。正如你所说,使用 either "named"

function foo({a = 'peanut', b = 'butter'} = {}) {
    console.log(a, b);
}

位置参数:

function foo(a = 'peanut', b = 'butter') {
    console.log(a, b);
}

选择更适合您功能的,不要混合使用两者


如果您出于某种原因确实需要两者,standard overloading techniques 可供您使用。只有当您的第一个位置参数不是对象时,它才会正常工作。我会提出以下成语之一:

function foo(a, b) { // positional is normal case
    if (arguments.length == 1 && typeof arguments[0] == "object")
        {a, b} = arguments[0];

    console.log(a, b);
}
function foo({a, b}) { // named is normal case
    if (arguments.length > 1 || typeof arguments[0] != "object")
        [a, b] = arguments;

    console.log(a, b);
}

如果你需要默认值,无论哪种方式都很难看:

function foo(a, b) {
    var opts = (arguments.length == 1 && typeof arguments[0] == "object")
      ? arguments[0]
      : {a, b};
    ({a = 'peanut', b = 'butter'} = opts);

    console.log(a, b);
}

【讨论】:

    【解决方案2】:

    我想这样的事情会起作用:

    function foo(...options){
       if (typeof options[0] === 'object'){
        console.log('expect object', options[0]);
      }else{
        console.log('expect array', options);  
      }
    }
    
    foo('peanut', 'butter');
    foo({a:'peanut', b:'butter'});
    

    【讨论】:

    • 这是有道理的。但是,如果我使用foo('hello'),我将拥有options.length === 1。那么如果我要检查options[0] 是否是一个对象,那么foo({'whatever': 'object'}) 也会失败。还有其他想法吗?
    • true,你也可以检查第一个参数的类型,如果它是一个对象typeof
    • 你是对的,但如果我希望a 无论如何都是一个对象呢?然后我会为a 传递一个对象,但随后它会被错误地识别为命名参数集。
    • 另外,typeof options[0] === 'object' 将打开一罐蠕虫:例如typeof null === 'object'
    • @AKG typeof new String() === "object" 考虑到您的参数要求,情况更糟
    【解决方案3】:

    我认为没有内置的东西,但这段代码应该适用于你的情况

    function foo({a = 'peanut', b = 'butter'} = {}) {
        if (typeof arguments[0] === 'string') {
            return foo({a: arguments[0], b: arguments[1]})
        }
        console.log(a, b);
    }
    

    【讨论】:

      猜你喜欢
      • 2022-10-07
      • 2021-05-14
      • 1970-01-01
      • 2016-01-08
      • 2010-11-19
      • 2012-04-14
      • 2017-06-30
      • 2011-08-30
      相关资源
      最近更新 更多