函数的 JavaScript 可变参数数

JavaScript variable number of arguments to function

提问人:Timo 提问时间:1/27/2010 最后编辑:bluishTimo 更新时间:7/11/2023 访问量:489224

问:

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

例:

load(var1, var2, var3, var4, var5, etc...)
load(var1)
JavaScript 函数 参数传递

评论

0赞 Nakilon 2/7/2013
可能的重复 是否可以向 JavaScript 函数发送可变数量的参数?
0赞 Luke 4/22/2015
相关/可能重复 stackoverflow.com/questions/4633125/...
1赞 Scruffy 1/2/2017
@Luke不,不是。该问题询问如何使用数组中的参数调用具有任意数量参数的函数。这询问如何处理此类呼叫。
7赞 gschenk 1/23/2020
为了便于搜索,这样的函数称为“可变调函数”。

答:

935赞 roufamatic 1/27/2010 #1

当然,只需使用对象即可。arguments

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

评论

5赞 User2 4/30/2014
这个解决方案最适合我。谢谢。有关 arguments 关键字的更多信息 这里.
39赞 Luke 4/22/2015
arguments是一个特殊的“类数组”对象,这意味着它有长度,但没有其他数组函数。有关详细信息,请参阅 developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/...,以及以下答案:stackoverflow.com/a/13145228/1766230
7赞 Stijn de Witt 11/11/2016
有趣的是,Javascript 中的 Array 方法的定义方式是,它们可以处理任何具有属性的对象。这包括对象。知道了这一点,并且该方法返回了它所调用的“数组”的副本,我们可以轻松地将对象转换为真正的数组,如下所示: .有些人更喜欢用,但我喜欢,它们短而甜美!lengthargumentsconcatargumentsvar args = [].concat.call(arguments)Array.prototype.concat.call[]
3赞 roufamatic 9/8/2017
@DavidGatti 从拇指下方的文本中:“这已弃用为 Function 的属性。请改用函数中可用的 arguments 对象。
4赞 Willian Andrade 7/22/2019
@YasirJan用途[...arguments].join()
7赞 nickytonline 1/27/2010 #2

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

20赞 Canavar 1/27/2010 #3

是的,就像这样:

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

load(1,2);
124赞 Ken 1/27/2010 #4

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

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

并像这样使用它

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

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

评论

4赞 Jonas Schubert Erlandsson 1/30/2013
这样会更好,因为它删除了与参数顺序的耦合。松散耦合接口是很好的标准做法...
10赞 rvighne 12/9/2013
当然,在某些情况下会更好。但是,假设各个参数彼此之间并不真正相关,或者都应该具有相同的含义(例如数组元素)。那么OP的方式是最好的。
1赞 Nate C-K 1/29/2014
这也很好,因为如果你愿意,你可以用代码构建参数,并在它被使用之前传递它。context
52赞 mbeasley 7/23/2012 #5

我同意 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];
}

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

评论

3赞 Neil 9/17/2012
+1.好把戏。节省了大量的样板,以定义每个参数,默认或其他参数。
1赞 mbeasley 2/14/2013
Underscore 的方法是合并指定参数和默认参数的一个很好的替代方法。_.defaults()
10赞 mcurland 2/8/2013 #6

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

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

   // do stuff
}

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

评论

0赞 mcurland 8/29/2014
同意,尽管损害取决于价值的类型或违约本身。否则,或者对于较少的代码量,可以使用一个小的帮助程序函数,例如: 提供备用模式。但是,我的观点仍然成立:为每个函数调用创建额外的对象并运行昂贵的循环来设置几个默认值是疯狂的开销。(parameter1=context.parameter1)===undefined && (parameter1=defaultValue1)function def(providedValue, default) {return providedValue !== undefined ? providedValue : defaultValue;} var parameter1 = def(context.parameter1, defaultValue1)
6赞 phbcanada 8/7/2014 #7

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

18赞 Peter Tseng 2/12/2016 #8

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

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

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

评论

0赞 Dmytro Medvid 2/13/2016
将参数转换为数组的不错解决方案。今天对我很有帮助。
340赞 Ramast 8/20/2016 #9

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

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

评论

42赞 tanguy_k 11/16/2016
仅供参考,它被称为“其余参数语法”:developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/...
4赞 haxpor 9/6/2017
+1 这是优雅而干净的解决方案。特别适用于将一长串参数传递到另一个函数调用中,并且这些变量参数可能位于任意位置。
4赞 Roee Gavirel 12/31/2018
请记住,根据 developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/...,IE不支持它。
3赞 Brian Burns 4/10/2019
下表显示了浏览器支持 - caniuse.com/#feat=rest-parameters
2赞 Marcin Wojnarski 9/7/2021
值得注意的是,语法不会分配给命名的参数(例如,在 Python 中会这样做),而是传递一个未命名的参数值创建一个具有相同值的局部变量作为副作用z='d'z'd'z
24赞 Nicola Pedretti 12/2/2016 #10

正如 Ramast 所指出的那样,最好使用 rest 参数语法。

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

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

  1. 它是一个数组,而不是像参数那样的对象。这允许您直接应用地图或排序等功能。
  2. 它不包括所有参数,而只包括从它传递的参数。例如,函数(a、b、...args) 在本例中,args 包含 参数 3 到 arguments.length
10赞 Brian Ellis 2/24/2017 #11

虽然@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“ rest 参数)

如答案顶部所述,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
0赞 Marcus Arthur 12/9/2021 #12

使用数组,然后您可以使用所需的参数数量。例如,计算数组中 number 元素的平均值:

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
1赞 Harshal Madgulkar 7/11/2023 #13

REST 参数

参考 Rest 参数 MDN

function addition(...numbers){
    var sum=0;
    for(var i=0;i<number.length;i++){
        sum+=numbers[i];
      }
    return sum;
    }

  console.log(sum);

评论

0赞 Community 7/13/2023
正如目前所写的那样,你的答案尚不清楚。请编辑以添加其他详细信息,以帮助其他人了解这如何解决所提出的问题。您可以在帮助中心找到有关如何写出好答案的更多信息。