是否有一种方法允许“无限”变量的函数在JavaScript?

例子:

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

当前回答

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

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

其他回答

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

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

像这样使用它

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

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

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

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

Although I generally agree that the named arguments approach is useful and flexible (unless you care about the order, in which case arguments is easiest), I do have concerns about the cost of the mbeasley approach (using defaults and extends). This is an extreme amount of cost to take for pulling default values. First, the defaults are defined inside the function, so they are repopulated on every call. Second, you can easily read out the named values and set the defaults at the same time using ||. There is no need to create and merge yet another new object to get this information.

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

   // do stuff
}

这是大致相同数量的代码(可能稍微多一点),但应该是运行时成本的一小部分。

虽然@roufamatic确实展示了arguments关键字的使用,@Ken展示了一个很好的对象使用示例,但我觉得两者都没有真正解决这个实例中发生的事情,并且可能会使未来的读者感到困惑,或者逐渐形成一个坏习惯,因为没有显式地说明一个函数/方法的目的是采用可变数量的参数/参数。

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

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

让我们显式地声明同一个函数有变量形参:

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

对象参数VS var_args

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

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

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

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