【问题标题】:JavaScript variable number of arguments to functionJavaScript 可变数量的函数参数
【发布时间】:2011-01-09 15:16:00
【问题描述】:

有没有办法允许 JavaScript 中的函数使用“无限”变量?

例子:

load(var1, var2, var3, var4, var5, etc...)
load(var1)

【问题讨论】:

标签: javascript function arguments argument-passing


【解决方案1】:

当然,只需使用 arguments 对象。

function foo() {
  for (var i = 0; i < arguments.length; i++) {
    console.log(arguments[i]);
  }
}

【讨论】:

  • 这个解决方案最适合我。谢谢。有关参数关键字HERE 的更多信息。
  • arguments 是一个特殊的“类数组”对象,这意味着它有一个长度,但没有其他数组函数。有关更多信息,请参阅developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…,这个答案:stackoverflow.com/a/13145228/1766230
  • 有趣的是,Javascript 中的 Array 方法被定义为可以在任何具有 length 属性的对象上工作。这包括arguments 对象。知道了这一点,并且concat 方法返回了它所调用的“数组”的一个副本,我们可以轻松地将arguments 对象转换为一个真正的数组,如下所示:var args = [].concat.call(arguments)。有些人喜欢用Array.prototype.concat.call代替,但我喜欢[],它们又短又甜!
  • 已弃用 此功能已从 Web 标准中删除。尽管某些浏览器可能仍然支持它,但它正在被删除。尽可能避免使用它并更新现有代码;请参阅本页底部的兼容性表以指导您的决定。请注意,此功能可能随时停止工作。
  • @YasirJan 使用[...arguments].join()
【解决方案2】:

在(大多数)最新浏览器中,您可以使用以下语法接受可变数量的参数:

function my_log(...args) {
     // args is an Array
     console.log(args);
     // You can pass this array as parameters to another function
     console.log(...args);
}

这是一个小例子:

function foo(x, ...args) {
  console.log(x, args, ...args, arguments);
}

foo('a', 'b', 'c', z='d')

=>

a
Array(3) [ "b", "c", "d" ]
b c d
Arguments
​    0: "a"
    ​1: "b"
    ​2: "c"
    ​3: "d"
    ​length: 4

此处的文档和更多示例:https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/rest_parameters

【讨论】:

【解决方案3】:

另一种选择是在上下文对象中传递参数。

function load(context)
{
    // do whatever with context.name, context.address, etc
}

并像这样使用它

load({name:'Ken',address:'secret',unused:true})

这样做的好处是您可以根据需要添加任意数量的命名参数,并且函数可以根据需要使用(或不使用)它们。

【讨论】:

  • 这会更好,因为它消除了与参数顺序的耦合。松散耦合的接口是很好的标准做法...
  • 当然,在某些情况下这样会更好。但是假设各个参数并不真正相互关联,或者都应该具有相同的含义(如数组元素)。那么OP的方式是最好的。
  • 这也很好,因为如果您愿意,您可以使用代码构建 context 参数并在使用之前传递它。
【解决方案4】:

我同意 Ken 的回答是最有活力的,我想更进一步。如果它是您使用不同参数多次调用的函数 - 我使用 Ken 的设计,然后添加默认值:

function load(context) {

    var defaults = {
        parameter1: defaultValue1,
        parameter2: defaultValue2,
        ...
    };

    var context = extend(defaults, context);

    // do stuff
}

这样,如果您有很多参数但不一定需要在每次调用函数时设置它们,您可以简单地指定非默认值。对于 extend 方法,您可以使用 jQuery 的 extend 方法 ($.extend()),自己制作或使用以下方法:

function extend() {
    for (var i = 1; i < arguments.length; i++)
        for (var key in arguments[i])
            if (arguments[i].hasOwnProperty(key))
                arguments[0][key] = arguments[i][key];
    return arguments[0];
}

这会将上下文对象与默认值合并,并使用默认值填充对象中任何未定义的值。

【讨论】:

  • +1。好把戏。节省大量样板来定义每个参数,默认或其他。
  • Underscore's _.defaults() 方法是合并指定参数和默认参数的一个非常好的替代方法。
【解决方案5】:

最好使用 Ramast 指出的 rest 参数语法。

function (a, b, ...args) {}

我只想为 ...args 参数添加一些不错的属性

  1. 它是一个数组,而不是像参数这样的对象。这允许您直接应用地图或排序等功能。
  2. 它不包括所有参数,而只包括从它传递的参数。例如。函数 (a, b, ...args) 在这种情况下 args 包含 arguments.length 的参数 3

【讨论】:

    【解决方案6】:

    是的,就像这样:

    function load()
    {
      var var0 = arguments[0];
      var var1 = arguments[1];
    }
    
    load(1,2);
    

    【讨论】:

      【解决方案7】:

      如前所述,您可以使用arguments 对象来检索可变数量的函数参数。

      如果您想使用相同的参数调用另一个函数,请使用apply。您甚至可以通过将arguments 转换为数组来添加或删除参数。例如,此函数在登录到控制台之前插入一些文本:

      log() {
          let args = Array.prototype.slice.call(arguments);
          args = ['MyObjectName', this.id_].concat(args);
          console.log.apply(console, args);
      }
      

      【讨论】:

      • 将参数转换为数组的好方法。今天对我很有帮助。
      【解决方案8】:

      虽然我通常同意命名参数方法有用且灵活(除非您关心顺序,在这种情况下参数最简单),但我确实担心 mbeasley 方法的成本(使用默认值和扩展)。这是拉取默认值的巨大成本。首先,默认值是在函数内部定义的,因此在每次调用时都会重新填充它们。其次,您可以使用 || 轻松读出命名值并同时设置默认值。无需创建和合并另一个新对象即可获取此信息。

      function load(context) {
         var parameter1 = context.parameter1 || defaultValue1,
             parameter2 = context.parameter2 || defaultValue2;
      
         // do stuff
      }
      

      这与代码量大致相同(可能略多一些),但应该只是运行时成本的一小部分。

      【讨论】:

      • 同意,尽管危害取决于值的类型或默认值本身。否则,(parameter1=context.parameter1)===undefined &amp;&amp; (parameter1=defaultValue1) 或对于更少的代码量,一个小的帮助函数,如:function def(providedValue, default) {return providedValue !== undefined ? providedValue : defaultValue;} var parameter1 = def(context.parameter1, defaultValue1) 提供替代模式。然而,我的观点仍然存在:为每个函数调用创建额外的对象并运行昂贵的循环来设置几个默认值是一个疯狂的开销。
      【解决方案9】:

      虽然@roufamatic 确实展示了 arguments 关键字的使用,而@Ken 展示了一个很好的使用对象示例,但我觉得既没有真正解决这种情况下发生的事情,也可能会混淆未来的读者,或者灌输一种不好的做法,因为没有明确说明声明一个函数/方法旨在采用可变数量的参数/参数。

      function varyArg () {
          return arguments[0] + arguments[1];
      }
      

      当其他开发人员查看您的代码时,很容易假设此函数不带参数。特别是如果该开发人员不知道 arguments 关键字。因此,遵循风格指南并保持一致是一个好主意。我将使用 Google 的所有示例。

      让我们明确声明同一个函数具有可变参数:

      function varyArg (var_args) {
          return arguments[0] + arguments[1];
      }
      

      对象参数VS var_args

      有时可能需要一个对象,因为它是唯一被批准和考虑的数据映射最佳实践方法。关联数组不受欢迎,不鼓励使用。

      旁注: arguments 关键字实际上返回一个使用数字作为键的对象。原型继承也是对象族。在 JS 中正确使用数组,请参阅答案结尾

      在这种情况下,我们也可以明确说明这一点。注意:此命名约定不是由 Google 提供的,而是显式声明参数类型的示例。如果您希望在代码中创建更严格的类型化模式,这一点很重要。

      function varyArg (args_obj) {
          return args_obj.name+" "+args_obj.weight;
      }
      varyArg({name: "Brian", weight: 150});
      

      选择哪一个?

      这取决于您的功能和程序的需要。例如,如果您只是希望基于所有传递的参数的迭代过程返回一个值,那么肯定会坚持使用 arguments 关键字。如果您需要定义参数和数据映射,那么对象方法就是要走的路。让我们看两个例子,然后我们就完成了!

      参数用法

      function sumOfAll (var_args) {
          return arguments.reduce(function(a, b) {
              return a + b;
          }, 0);
      }
      sumOfAll(1,2,3); // returns 6
      

      对象使用

      function myObjArgs(args_obj) {
          // MAKE SURE ARGUMENT IS AN OBJECT OR ELSE RETURN
          if (typeof args_obj !== "object") {
              return "Arguments passed must be in object form!";
          }
      
          return "Hello "+args_obj.name+" I see you're "+args_obj.age+" years old.";
      }
      myObjArgs({name: "Brian", age: 31}); // returns 'Hello Brian I see you're 31 years old
      

      访问数组而不是对象(“...args”其余参数)

      如答案顶部所述,arguments 关键字实际上返回一个对象。因此,必须调用任何您想用于数组的方法。一个例子:

      Array.prototype.map.call(arguments, function (val, idx, arr) {});
      

      为避免这种情况,请使用 rest 参数:

      function varyArgArr (...var_args) {
          return var_args.sort();
      }
      varyArgArr(5,1,3); // returns 1, 3, 5
      

      【讨论】:

        【解决方案10】:

        在函数内部使用arguments 对象可以访问所有传入的参数。

        【讨论】:

          【解决方案11】:

          请注意,按照 Ken 的建议传递具有命名属性的对象会增加为每次调用分配和释放临时对象的成本。通过值或引用传递普通参数通常是最有效的。对于许多应用程序来说,虽然性能并不重要,但对于某些应用程序来说可能是关键。

          【讨论】:

            【解决方案12】:

            使用数组,然后你可以使用你需要多少个参数。例如,计算数组元素个数的平均值:

            function fncAverage(sample) {
                var lenghtSample = sample.length;
                var elementsSum = 0;
                for (var i = 0; i < lenghtSample; i++) {
                    elementsSum = Number(elementsSum) + Number(sample[i]);
                }
                average = elementsSum / lenghtSample
                return (average);
            }
            
            console.log(fncAverage([1, 2, 3, 4, 5, 6, 7, 8, 9, 10])); // results 5.5
            
            let mySample = [10, 20, 30, 40];
            console.log(fncAverage(mySample)); // results 25
            
            //try your own arrays of numbers
            

            【讨论】:

              猜你喜欢
              • 2023-03-12
              • 2015-03-24
              • 2011-10-12
              • 2023-03-28
              • 1970-01-01
              • 2022-12-11
              • 2013-12-23
              • 2013-08-07
              相关资源
              最近更新 更多