简体   繁体   English

JavaScript 可变数量的函数参数

[英]JavaScript variable number of arguments to function

Is there a way to allow "unlimited" vars for a function in JavaScript?有没有办法允许 JavaScript 中的函数的“无限”变量?

Example:例子:

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

Sure, just use the arguments object.当然,只需使用arguments对象。

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

In (most) recent browsers, you can accept variable number of arguments with this syntax:在(大多数)最近的浏览器中,您可以使用以下语法接受可变数量的参数:

function my_log(...args) {
     // args is an Array
     console.log(args);
     // You can pass this array as parameters to another function
     console.log(...args);
}

Here's a small example:这是一个小例子:

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

Documentation and more examples here: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/rest_parameters此处的文档和更多示例: https : //developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/rest_parameters

Another option is to pass in your arguments in a context object.另一种选择是在上下文对象中传递参数。

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

and use it like this并像这样使用它

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

This has the advantage that you can add as many named arguments as you want, and the function can use them (or not) as it sees fit.这样做的好处是您可以根据需要添加任意数量的命名参数,并且函数可以根据需要使用(或不使用)它们。

I agree with Ken's answer as being the most dynamic and I like to take it a step further.我同意 Ken 的回答是最有活力的,我喜欢更进一步。 If it's a function that you call multiple times with different arguments - I use Ken's design but then add default values:如果它是一个使用不同参数多次调用的函数 - 我使用 Ken 的设计,然后添加默认值:

function load(context) {

    var defaults = {
        parameter1: defaultValue1,
        parameter2: defaultValue2,
        ...
    };

    var context = extend(defaults, context);

    // do stuff
}

This way, if you have many parameters but don't necessarily need to set them with each call to the function, you can simply specify the non-defaults.这样,如果您有许多参数但不一定需要在每次调用函数时都设置它们,您可以简单地指定非默认值。 For the extend method, you can use jQuery's extend method ( $.extend() ), craft your own or use the following:对于扩展方法,您可以使用 jQuery 的扩展方法( $.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];
}

This will merge the context object with the defaults and fill in any undefined values in your object with the defaults.这会将上下文对象与默认值合并,并使用默认值填充对象中的任何未定义值。

It is preferable to use rest parameter syntax as Ramast pointed out.正如 Ramast 指出的那样,最好使用 rest 参数语法。

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

I just want to add some nice property of the ...args argument我只想添加 ...args 参数的一些不错的属性

  1. It is an array, and not an object like arguments.它是一个数组,而不是像参数这样的对象。 This allows you to apply functions like map or sort directly.这允许您直接应用 map 或 sort 等功能。
  2. It does not include all parameters but only the one passed from it on.它不包括所有参数,而只包括从它传递过来的参数。 Eg function (a, b, ...args) in this case args contains argument 3 to arguments.length例如 function (a, b, ...args) 在这种情况下 args 包含参数 3 到arguments.length

Yes, just like this :是的,就像这样:

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

load(1,2);

As mentioned already, you can use the arguments object to retrieve a variable number of function parameters.如前所述,您可以使用arguments对象来检索可变数量的函数参数。

If you want to call another function with the same arguments, use apply .如果要使用相同的参数调用另一个函数,请使用apply You can even add or remove arguments by converting arguments to an array.您甚至可以通过将arguments转换为数组来添加或删除参数。 For example, this function inserts some text before logging to console:例如,此函数在登录到控制台之前插入一些文本:

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

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).尽管我普遍同意命名参数方法有用且灵活(除非您关心顺序,在这种情况下参数是最简单的),但我确实担心 mbeasley 方法(使用默认值和扩展)的成本。 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
}

This is roughly the same amount of code (maybe slightly more), but should be a fraction of the runtime cost.这与代码量大致相同(可能略多),但应该是运行时成本的一小部分。

While @roufamatic did show use of the arguments keyword and @Ken showed a great example of an object for usage I feel neither truly addressed what is going on in this instance and may confuse future readers or instill a bad practice as not explicitly stating a function/method is intended to take a variable amount of arguments/parameters.虽然@roufamatic 确实展示了arguments 关键字的使用,而@Ken 展示了一个很好的使用对象示例,但我觉得这两个例子都没有真正解决这个例子中发生的事情,并且可能会让未来的读者感到困惑,或者灌输一种不好的做法,因为没有明确说明一个函数/method 旨在采用可变数量的参数/参数。

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

When another developer is looking through your code is it very easy to assume this function does not take parameters.当其他开发人员查看您的代码时,很容易假设此函数不带参数。 Especially if that developer is not privy to the arguments keyword.特别是如果该开发人员不知道参数关键字。 Because of this it is a good idea to follow a style guideline and be consistent.因此,遵循风格指南并保持一致是个好主意。 I will be using Google's for all examples.我将在所有示例中使用 Google 的。

Let's explicitly state the same function has variable parameters:让我们明确声明相同的函数具有可变参数:

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

Object parameter VS var_args对象参数 VS var_args

There may be times when an object is needed as it is the only approved and considered best practice method of an data map.有时可能需要一个对象,因为它是唯一被批准和考虑的数据映射最佳实践方法。 Associative arrays are frowned upon and discouraged.关联数组是不受欢迎和不鼓励的。

SIDENOTE: The arguments keyword actually returns back an object using numbers as the key.旁注: arguments 关键字实际上返回一个使用数字作为键的对象。 The prototypal inheritance is also the object family.原型继承也是对象家族。 See end of answer for proper array usage in JS有关 JS 中正确使用数组的信息,请参阅答案结尾

In this case we can explicitly state this also.在这种情况下,我们也可以明确说明这一点。 Note: this naming convention is not provided by Google but is an example of explicit declaration of a param's type.注意:此命名约定不是由 Google 提供的,而是显式声明参数类型的示例。 This is important if you are looking to create a more strict typed pattern in your code.如果您希望在代码中创建更严格的类型化模式,这一点很重要。

function varyArg (args_obj) {
    return args_obj.name+" "+args_obj.weight;
}
varyArg({name: "Brian", weight: 150});

Which one to choose?选择哪一个?

This depends on your function's and program's needs.这取决于您的函数和程序的需要。 If for instance you are simply looking to return a value base on an iterative process across all arguments passed then most certainly stick with the arguments keyword.例如,如果您只是想根据传递的所有参数的迭代过程返回一个值,那么肯定会坚持使用arguments关键字。 If you need definition to your arguments and mapping of the data then the object method is the way to go.如果您需要定义参数和映射数据,那么对象方法就是您要走的路。 Let's look at two examples and then we're done!让我们看两个例子,然后我们就完成了!

Arguments usage参数用法

function sumOfAll (var_args) {
    return arguments.reduce(function(a, b) {
        return a + b;
    }, 0);
}
sumOfAll(1,2,3); // returns 6

Object usage对象使用

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

Accessing an array instead of an object ("...args" The rest parameter)访问数组而不是对象("...args" 其余参数)

As mentioned up top of the answer the arguments keyword actually returns an object.正如在答案顶部提到的, arguments关键字实际上返回一个对象。 Because of this any method you want to use for an array will have to be called.因此,您要用于数组的任何方法都必须被调用。 An example of this:这方面的一个例子:

Array.prototype.map.call(arguments, function (val, idx, arr) {});

To avoid this use the rest parameter:为避免这种情况,请使用 rest 参数:

function varyArgArr (...var_args) {
    return var_args.sort();
}
varyArgArr(5,1,3); // returns 1, 3, 5

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

Be aware that passing an Object with named properties as Ken suggested adds the cost of allocating and releasing the temporary object to every call.请注意,按照 Ken 的建议传递具有命名属性的对象会增加为每次调用分配和释放临时对象的成本。 Passing normal arguments by value or reference will generally be the most efficient.通过值或引用传递普通参数通常是最有效的。 For many applications though the performance is not critical but for some it can be.对于许多应用程序,虽然性能并不重要,但对于某些应用程序来说可能是。

Use array and then you can use how many parameters you need.使用数组,然后您可以使用您需要的参数数量。 For example, calculate the average of the number elements of an array:例如,计算数组元素个数的平均值:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM