提问人:Timo 提问时间:1/27/2010 最后编辑:bluishTimo 更新时间:7/11/2023 访问量:489224
函数的 JavaScript 可变参数数
JavaScript variable number of arguments to function
问:
有没有办法在 JavaScript 中允许函数使用“无限”变量?
例:
load(var1, var2, var3, var4, var5, etc...)
load(var1)
答:
当然,只需使用对象即可。arguments
function foo() {
for (var i = 0; i < arguments.length; i++) {
console.log(arguments[i]);
}
}
评论
arguments
是一个特殊的“类数组”对象,这意味着它有长度,但没有其他数组函数。有关详细信息,请参阅 developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/...,以及以下答案:stackoverflow.com/a/13145228/1766230
length
arguments
concat
arguments
var args = [].concat.call(arguments)
Array.prototype.concat.call
[]
[...arguments].join()
在函数内部使用该对象来访问传入的所有参数。arguments
是的,就像这样:
function load()
{
var var0 = arguments[0];
var var1 = arguments[1];
}
load(1,2);
另一种选择是在上下文对象中传入参数。
function load(context)
{
// do whatever with context.name, context.address, etc
}
并像这样使用它
load({name:'Ken',address:'secret',unused:true})
这样做的好处是,您可以根据需要添加任意数量的命名参数,并且函数可以根据需要使用它们(或不使用它们)。
评论
context
我同意 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];
}
这会将上下文对象与默认值合并,并使用默认值填充对象中任何未定义的值。
评论
虽然我通常同意命名参数方法是有用且灵活的(除非您关心顺序,在这种情况下,参数是最简单的),但我确实担心 mbeasley 方法(使用默认值和扩展)的成本。这是提取默认值的极高成本。首先,默认值是在函数内部定义的,因此在每次调用时都会重新填充它们。其次,您可以使用 ||轻松读出命名值并同时设置默认值。无需创建和合并另一个新对象即可获取此信息。
function load(context) {
var parameter1 = context.parameter1 || defaultValue1,
parameter2 = context.parameter2 || defaultValue2;
// do stuff
}
这大致相同(可能略多),但应该是运行时成本的一小部分。
评论
(parameter1=context.parameter1)===undefined && (parameter1=defaultValue1)
function def(providedValue, default) {return providedValue !== undefined ? providedValue : defaultValue;} var parameter1 = def(context.parameter1, defaultValue1)
请注意,按照 Ken 的建议传递具有命名属性的 Object,会增加为每次调用分配和释放临时对象的成本。按值或引用传递普通参数通常是最有效的。对于许多应用来说,性能并不重要,但对于某些应用来说,性能可能很重要。
如前所述,您可以使用该对象来检索可变数量的函数参数。arguments
如果要调用具有相同参数的另一个函数,请使用 。您甚至可以通过转换为数组来添加或删除参数。例如,此函数在记录到控制台之前插入一些文本:apply
arguments
log() {
let args = Array.prototype.slice.call(arguments);
args = ['MyObjectName', this.id_].concat(args);
console.log.apply(console, args);
}
评论
在(大多数)最近的浏览器中,您可以使用以下语法接受可变数量的参数:
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
评论
z='d'
z
'd'
z
正如 Ramast 所指出的那样,最好使用 rest 参数语法。
function (a, b, ...args) {}
我只想添加一些不错的属性......args 参数
- 它是一个数组,而不是像参数那样的对象。这允许您直接应用地图或排序等功能。
- 它不包括所有参数,而只包括从它传递的参数。例如,函数(a、b、...args) 在本例中,args 包含 参数 3 到 arguments.length
虽然@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
使用数组,然后您可以使用所需的参数数量。例如,计算数组中 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
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);
评论