JavaScript variable number of arguments to function
有没有办法允许JavaScript中的函数"无限"变量?
例:
1 2 | load(var1, var2, var3, var4, var5, etc...) load(var1) |
当然,只需使用
1 2 3 4 5 | function foo() { for (var i = 0; i < arguments.length; i++) { console.log(arguments[i]); } } |
在(大多数)最近的浏览器中,您可以使用以下语法接受可变数量的参数:
1 2 3 4 5 6 | function my_log(...args) { // args is an Array console.log(args); // You can pass this array as parameters to another function console.log(...args); } |
这是一个小例子:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | 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
另一种选择是在上下文对象中传入您的参数。
1 2 3 4 | function load(context) { // do whatever with context.name, context.address, etc } |
并像这样使用它
1 | load({name:'Ken',address:'secret',unused:true}) |
这样做的好处是,您可以根据需要添加任意数量的命名参数,并且该函数可以根据需要使用它们(或不使用它们)。
我同意Ken的答案是最有活力的,我更愿意更进一步。如果它是一个你用不同的参数多次调用的函数 - 我使用Ken的设计但是然后添加默认值:
1 2 3 4 5 6 7 8 9 10 11 12 | function load(context) { var defaults = { parameter1: defaultValue1, parameter2: defaultValue2, ... }; var context = extend(defaults, context); // do stuff } |
这样,如果您有许多参数但不一定需要在每次调用函数时设置它们,您只需指定非默认值即可。对于extend方法,您可以使用jQuery的extend方法(
1 2 3 4 5 6 7 | 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 2 3 4 5 6 7 | function load() { var var0 = arguments[0]; var var1 = arguments[1]; } load(1,2); |
正如Ramast指出的那样,最好使用rest参数语法。
1 | function (a, b, ...args) {} |
我只是想添加... args参数的一些不错的属性
It is an array, and not an object like arguments. This allows you to apply functions like map or sort directly. It does not include all parameters but only the one passed from it on. E.g. function (a, b, ...args) in this case args contains
argument 3 to arguments.length
如前所述,您可以使用
如果要使用相同的参数调用另一个函数,请使用
1 2 3 4 5 | log() { let args = Array.prototype.slice.call(arguments); args = ['MyObjectName', this.id_].concat(args); console.log.apply(console, args); } |
虽然我普遍认为命名参数方法是有用且灵活的(除非你关心顺序,在这种情况下参数最简单),但我确实担心mbeasley方法的成本(使用默认值和扩展)。这是拉动默认值所需的极高成本。首先,默认值在函数内定义,因此它们在每次调用时都会重新填充。其次,您可以使用||轻松读出命名值并同时设置默认值。无需创建和合并另一个新对象即可获取此信息。
1 2 3 4 5 6 | function load(context) { var parameter1 = context.parameter1 || defaultValue1, parameter2 = context.parameter2 || defaultValue2; // do stuff } |
这大致相同的代码量(可能略多),但应该是运行时成本的一小部分。
虽然@roufamatic确实显示了arguments关键字的使用,而且@Ken显示了一个使用对象的一个??很好的例子,我觉得它并没有真正解决这个实例中发生的事情,可能会混淆未来的读者或灌输一个不好的做法,因为没有明确说明一个函数/ method旨在获取可变数量的参数/参数。
1 2 3 | function varyArg () { return arguments[0] + arguments[1]; } |
当另一个开发人员查看您的代码时,很容易假设此函数不接受参数。特别是如果该开发人员不知道arguments关键字。因此,遵循风格指南并保持一致是个好主意。我将使用Google的所有示例。
让我们明确说明同一个函数有变量参数:
1 2 3 | function varyArg (var_args) { return arguments[0] + arguments[1]; } |
对象参数VS var_args
有时可能需要一个对象,因为它是数据映射中唯一经过批准和考虑的最佳实践方法。关联数组不受欢迎并且不鼓励。
SIDENOTE:arguments关键字实际上使用数字作为键返回一个对象。原型继承也是对象家族。请参阅答案的结尾以了解JS中正确的数组使用情况
在这种情况下,我们也可以明确说明这一点。注意:此命名约定不是由Google提供的,而是显式声明param类型的示例。如果您希望在代码中创建更严格的类型模式,这一点很重要。
1 2 3 4 | function varyArg (args_obj) { return args_obj.name+""+args_obj.weight; } varyArg({name:"Brian", weight: 150}); |
哪一个选择?
这取决于您的功能和程序的需求。例如,如果你只想在迭代过程中返回所有传递的参数的值,那么肯定会坚持使用arguments关键字。如果您需要定义参数和数据映射,那么对象方法就是您的选择。让我们看看两个例子,然后我们就完成了!
参数用法
1 2 3 4 5 6 | function sumOfAll (var_args) { return arguments.reduce(function(a, b) { return a + b; }, 0); } sumOfAll(1,2,3); // returns 6 |
对象用法
1 2 3 4 5 6 7 8 9 | 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关键字实际上返回一个对象。因此,必须调用要用于数组的任何方法。一个例子:
1 | Array.prototype.map.call(arguments, function (val, idx, arr) {}); |
要避免这种情况,请使用rest参数:
1 2 3 4 | function varyArgArr (...var_args) { return var_args.sort(); } varyArgArr(5,1,3); // returns 1, 3, 5 |
在函数内部使用
请注意,将具有命名属性的对象作为Ken建议传递会增加为每个调用分配和释放临时对象的成本。通过值或引用传递正常参数通常是最有效的。对于许多应用程序虽然性能并不重要但对某些应用程序来说可能是。