简体   繁体   English

是否可以向 JavaScript 函数发送可变数量的参数?

[英]Is it possible to send a variable number of arguments to a JavaScript function?

Is it possible to send a variable number of arguments to a JavaScript function, from an array?是否可以从数组向 JavaScript 函数发送可变数量的参数?

var arr = ['a','b','c']

var func = function()
{
    // debug 
    alert(arguments.length);
    //
    for(arg in arguments)
        alert(arg);
}

func('a','b','c','d'); // prints 4 which is what I want, then 'a','b','c','d'
func(arr); // prints 1, then 'Array'

I've recently written a lot of Python and it's a wonderful pattern to be able to accept varargs and send them.我最近写了很多 Python,能够接受可变参数并发送它们是一个很棒的模式。 eg例如

def func(*args):
   print len(args)
   for i in args:
       print i

func('a','b','c','d'); // prints 4 which is what I want, then 'a','b','c','d'
func(*arr) // prints 4 which is what I want, then 'a','b','c','d'

Is it possible in JavaScript to send an array to be treated as the arguments array?在 JavaScript 中是否可以发送一个数组作为参数数组?

Update : Since ES6, you can simply use the spread syntax when calling the function:更新:从 ES6 开始,您可以在调用函数时简单地使用spread 语法

func(...arr);

Since ES6 also if you expect to treat your arguments as an array, you can also use the spread syntax in the parameter list, for example:由于 ES6 同样,如果您希望将参数视为数组,您还可以在参数列表中使用 spread 语法,例如:

function func(...args) {
  args.forEach(arg => console.log(arg))
}

const values = ['a', 'b', 'c']
func(...values)
func(1, 2, 3)

And you can combine it with normal parameters, for example if you want to receive the first two arguments separately and the rest as an array:并且您可以将它与普通参数结合使用,例如,如果您想分别接收前两个参数并将其余参数作为数组接收:

function func(first, second, ...theRest) {
  //...
}

And maybe is useful to you, that you can know how many arguments a function expects:也许对你有用,你可以知道一个函数需要多少个参数:

var test = function (one, two, three) {}; 
test.length == 3;

But anyway you can pass an arbitrary number of arguments...但无论如何你可以传递任意数量的参数......

The spread syntax is shorter and "sweeter" than apply and if you don't need to set the this value in the function call, this is the way to go.传播语法比apply更短、更“甜蜜”,如果您不需要在函数调用中设置this值,这就是要走的路。

Here is an apply example, which was the former way to do it:这是一个应用示例,这是以前的方法:

var arr = ['a','b','c'];

function func() {
  console.log(this); // 'test'
  console.log(arguments.length); // 3

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

};

func.apply('test', arr);

Nowadays I only recommend using apply only if you need to pass an arbitrary number of arguments from an array and set the this value.现在,我只建议仅在需要从数组中传递任意数量的参数设置this值时才使用apply apply takes is the this value as the first arguments, which will be used on the function invocation, if we use null in non-strict code, the this keyword will refer to the Global object (window) inside func , in strict mode, when explicitly using 'use strict' or in ES modules, null will be used. applythis值作为第一个参数,将在函数调用时使用,如果我们在非严格代码中使用null ,则this关键字将引用func内部的全局对象(窗口),在严格模式下,当明确使用 'use strict' 或在 ES 模块中,将使用null

Also note that the arguments object is not really an Array, you can convert it by:另请注意, arguments对象并不是真正的数组,您可以通过以下方式转换它:

var argsArray = Array.prototype.slice.call(arguments);

And in ES6:在 ES6 中:

const argsArray = [...arguments] // or Array.from(arguments)

But you rarely use the arguments object directly nowadays thanks to the spread syntax.但是由于扩展语法,您现在很少直接使用arguments对象。

You can actually pass as many values as you want to any javascript function.实际上,您可以将任意数量的值传递给任何 javascript 函数。 The explicitly named parameters will get the first few values, but ALL parameters will be stored in the arguments array.显式命名的参数将获得前几个值,但所有参数都将存储在参数数组中。

To pass the arguments array in "unpacked" form, you can use apply, like so (cf Functional Javascript ):要以“解压”形式传递参数数组,您可以使用 apply,如下所示(参见Functional Javascript ):

var otherFunc = function() {
   alert(arguments.length); // Outputs: 10
}

var myFunc = function() {
  alert(arguments.length); // Outputs: 10
  otherFunc.apply(this, arguments);
}
myFunc(1,2,3,4,5,6,7,8,9,10);

The splat and spread operators are part of ES6, the planned next version of Javascript. splatspread运算符是 ES6 的一部分,ES6 是计划中的 Javascript 的下一个版本。 So far only Firefox supports them.到目前为止,只有 Firefox 支持它们。 This code works in FF16+:此代码适用于 FF16+:

var arr = ['quick', 'brown', 'lazy'];

var sprintf = function(str, ...args)
{
    for (arg of args) {
        str = str.replace(/%s/, arg);
    }
    return str;
}

sprintf.apply(null, ['The %s %s fox jumps over the %s dog.', ...arr]);
sprintf('The %s %s fox jumps over the %s dog.', 'slow', 'red', 'sleeping');

Note the awkard syntax for spread.请注意传播的尴尬语法。 The usual syntax of sprintf('The %s %s fox jumps over the %s dog.', ...arr); sprintf('The %s %s fox jumps over the %s dog.', ...arr);的常用语法is not yet supported .尚不支持 You can find an ES6 compatibility table here .您可以在此处找到ES6 兼容性表

Note also the use of for...of , another ES6 addition.还要注意for...of的使用,这是 ES6 的另一个补充。 Using for...in for arrays is a bad idea .对数组使用for...in个坏主意

There are two methods as of ES2015. ES2015 有两种方法。

The arguments Object arguments对象

This object is built into functions, and it refers to, appropriately, the arguments of a function.该对象内置于函数中,它适当地引用了函数的参数。 It is not technically an array, though, so typical array operations won't work on it.不过,从技术上讲,它不是数组,因此典型的数组操作不适用于它。 The suggested method is to use Array.from or the spread operator to create an array from it.建议的方法是使用Array.from或扩展运算符从它创建一个数组。

I've seen other answers mention using slice .我已经看到其他答案提到使用slice Don't do that.不要那样做。 It prevents optimizations (source: MDN ).它会阻止优化(来源: MDN )。

Array.from(arguments)
[...arguments]

However, I would argue that arguments is problematic because it hides what a function accepts as input.但是,我认为arguments是有问题的,因为它隐藏了函数接受的输入。 An arguments function typically is written like this:一个arguments函数通常是这样写的:

function mean(){
    let args = [...arguments];
    return args.reduce((a,b)=>a+b) / args.length;
}

Sometimes, the function header is written like the following to document the arguments in a C-like fashion:有时,函数头的编写方式如下,以类似 C 的方式记录参数:

function mean(/* ... */){ ... }

But that is rare.但这很少见。

As for why it is problematic, take C, for example.至于为什么会出问题,就拿C来说吧。 C is backwards compatible with an ancient pre-ANSI dialect of the language known as K&R C. K&R C allows function prototypes to have an empty arguments list. C 向后兼容 K&R C 语言的一种古老的 pre-ANSI 方言。 K&R C 允许函数原型具有空参数列表。

int myFunction();
/* This function accepts unspecified parameters */

ANSI C provides a facility for varargs ( ... ), and void to specify an empty arguments-list. ANSI C 为varargs ( ... ) 和void提供了一个工具来指定一个空的参数列表。

int myFunction(void);
/* This function accepts no parameters */

Many people inadvertently declare functions with an unspecified arguments list ( int myfunction(); ), when they expect the function to take zero arguments.许多人不经意地用unspecified参数列表 ( int myfunction(); ) 声明函数,因为他们希望函数采用零参数。 This is technically a bug because the function will accept arguments.这在技术上是一个错误,因为该函数接受参数。 Any number of them.任意数量。

A proper varargs function in C takes the form: C 中适当的varargs函数采用以下形式:

int myFunction(int nargs, ...);

And JavaScript actually does have something similar to this. JavaScript 确实有类似的东西。

Spread Operator / Rest Parameters 扩展运算符/ 其余参数

I've already shown you the spread operator, actually.实际上,我已经向您展示了价差运算符。

...name

It's pretty versatile, and can also be used in a function's argument-list ("rest parameters") to specify varargs in a nicely documented fashion:它非常通用,也可以用在函数的参数列表(“其余参数”)中,以记录良好的方式指定可变参数:

function mean(...args){
    return args.reduce((a,b)=>a+b) / args.length;
}

Or as a lambda expression:或者作为 lambda 表达式:

((...args)=>args.reduce((a,b)=>a+b) / args.length)(1,2,3,4,5); // 3

I much prefer the spread operator.我更喜欢传播运算符。 It is clean and self-documenting.它是干净的和自我记录的。

The apply function takes two arguments; apply函数接受两个参数; the object this will be binded to, and the arguments, represented with an array. this将绑定到的对象,以及用数组表示的参数。

some_func = function (a, b) { return b }
some_func.apply(obj, ["arguments", "are", "here"])
// "are"

It's called the splat operator.它被称为splat运算符。 You can do it in JavaScript using apply :你可以在 JavaScript 中使用apply

var arr = ['a','b','c','d'];
var func = function() {
    // debug 
    console.log(arguments.length);
    console.log(arguments);
}
func('a','b','c','d'); // prints 4 which is what I want, then 'a','b','c','d'
func(arr); // prints 1, then 'Array'
func.apply(null, arr); 

With ES6 you can use rest parameters for varagrs .使用 ES6,您可以为varagrs使用rest 参数 This takes the argument list and converts it to an array.这需要参数列表并将其转换为数组。

function logArgs(...args) {
    console.log(args.length)
    for(let arg of args) {
        console.log(arg)
    }
}
(function(window) {
  var proxied = window.alert;
  window.alert = function() {
    return proxied.apply(window, arguments);
  };
}(this));

alert(13, 37);

This is a sample program for calculating sum of integers for variable arguments and array on integers.这是一个用于计算变量参数和整数数组的整数总和的示例程序。 Hope this helps.希望这可以帮助。

var CalculateSum = function(){
    calculateSumService.apply( null, arguments );
}

var calculateSumService = function(){
    var sum = 0;

    if( arguments.length === 1){
        var args = arguments[0];

        for(var i = 0;i<args.length; i++){
           sum += args[i]; 
        }
    }else{
        for(var i = 0;i<arguments.length; i++){
           sum += arguments[i]; 
        }        
    }

     alert(sum);

}


//Sample method call

// CalculateSum(10,20,30);         

// CalculateSum([10,20,30,40,50]);

// CalculateSum(10,20);

For those who were redirected here from Passing variable number of arguments from one function to another (which should not be marked as a duplicate of this question):对于那些谁是从重定向到这里传递的参数变量数量从一个功能到另一个(这应该被标记为这个问题的副本):

If you're trying to pass a variable number of arguments from one function to another, since JavaScript 1.8.5 you can simply call apply() on the second function and pass in the arguments parameter:如果您尝试将可变数量的参数从一个函数传递到另一个函数,从 JavaScript 1.8.5 开始,您可以简单地在第二个函数上调用apply()并传入arguments参数:

var caller = function()
{
    callee.apply( null, arguments );
}

var callee = function()
{
    alert( arguments.length );
}

caller( "Hello", "World!", 88 ); // Shows "3".

Note: The first argument is the this parameter to use.注意:第一个参数是要使用的this参数。 Passing null will call the function from the global context, ie as a global function instead of the method of some object.传递null将从全局上下文调用函数,即作为全局函数而不是某个对象的方法。

According to this document , the ECMAScript 5 specification redefined the apply() method to take any "generic array-like object", instead of strictly an Array.根据本文档,ECMAScript 5 规范重新定义了apply()方法以采用任何“通用类数组对象”,而不是严格意义上的数组。 Thus, you can directly pass the arguments list into the second function.因此,您可以直接将arguments列表传递给第二个函数。

Tested in Chrome 28.0, Safari 6.0.5, and IE 10. Try it out with this JSFiddle .在 Chrome 28.0、Safari 6.0.5 和 IE 10 中测试。用这个 JSFiddle 试试

Yes you can pass variable no.是的,您可以传递变量号。 of arguments to a function.函数的参数。 You can use apply to achieve this.您可以使用apply来实现这一点。

Eg:例如:

var arr = ["Hi","How","are","you"];

function applyTest(){
    var arg = arguments.length;
    console.log(arg);
}

applyTest.apply(null,arr);

Do you want your function to react to an array argument or variable arguments?你想让你的函数对数组参数或变量参数做出反应吗? If the latter, try:如果是后者,请尝试:

var func = function(...rest) {
  alert(rest.length);

  // In JS, don't use for..in with arrays
  // use for..of that consumes array's pre-defined iterator
  // or a more functional approach
  rest.forEach((v) => console.log(v));
};

But if you wish to handle an array argument但是如果你想处理一个数组参数

var fn = function(arr) {
  alert(arr.length);

  for(var i of arr) {
    console.log(i);
  }
};

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

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