605

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

例子:

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

12 回答 12

893

当然,只需使用arguments对象。

function foo() {
  for (var i = 0; i < arguments.length; i++) {
    console.log(arguments[i]);
  }
}
于 2010-01-26T18:08:04.823 回答
283

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

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

于 2016-08-20T04:46:27.027 回答
120

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

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

并像这样使用它

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

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

于 2010-01-26T18:34:14.343 回答
49

我同意肯的回答是最有活力的,我想更进一步。如果它是您使用不同参数多次调用的函数 - 我使用 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];
}

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

于 2012-07-23T14:11:39.717 回答
22

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

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

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

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

是的,就像这样:

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

load(1,2);
于 2010-01-26T18:08:12.857 回答
18

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

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

log() {
    let args = Array.prototype.slice.call(arguments);
    args = ['MyObjectName', this.id_].concat(args);
    console.log.apply(console, args);
}
于 2016-02-12T02:27:41.017 回答
10

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

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

   // do stuff
}

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

于 2013-02-07T21:59:37.570 回答
9

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

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

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

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

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
于 2017-02-24T03:47:59.853 回答
7

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

于 2010-01-26T18:08:08.083 回答
6

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

于 2014-08-06T20:25:50.417 回答
0

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

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
于 2021-12-08T18:26:32.073 回答