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

Posted

技术标签:

【中文标题】是否可以向 JavaScript 函数发送可变数量的参数?【英文标题】:Is it possible to send a variable number of arguments to a JavaScript function? 【发布时间】:2010-12-29 20:45:12 【问题描述】:

是否可以从数组中向 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'

我最近写了很多 Python 并且能够接受可变参数并发送它们是一个很棒的模式。例如

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'

是否可以在 JavaScript 中发送一个数组以将其视为 参数数组?

【问题讨论】:

请注意,将 for - in 循环与 arguments 对象一起使用不是一个好主意 - 应该使用“普通”循环迭代 length 属性来代替 从来都不是问题,你能详细说明为什么会这样吗? arguments 对象几乎总是足够小,使用 agruments[0..length-1] 版本的性能提升可以忽略不计。 JavaScript variable number of arguments to function的可能重复 我认为 arguments 不是一个实际的数组,而是一个特殊的对象,所以“in”语法可能不起作用,具体取决于 JS 实现。 【参考方案1】:

更新:从 ES6 开始,调用函数时可以简单地使用spread syntax

func(...arr);

由于 ES6 也如果您希望将参数视为数组,您还可以在参数列表中使用扩展语法,例如:

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


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

您可以将它与普通参数结合使用,例如,如果您想分别接收前两个参数,其余作为数组接收:

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

也许对你有用,你可以知道一个函数需要多少个参数:

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

但无论如何你可以传递任意数量的参数...

展开语法比apply 更短更“甜”,如果您不需要在函数调用中设置this 值,这就是要走的路。

这是一个apply 示例,这是以前的方法:

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);

现在我只推荐使用apply,仅当您需要从数组中传递任意数量的参数设置this 值。 applythis 值作为第一个参数,将在函数调用时使用,如果我们在非严格代码中使用nullthis 关键字将引用全局对象(窗口)在 func 内部,在严格模式下,当显式使用 'use strict' 或在 ES 模块中时,将使用 null

还要注意arguments 对象并不是真正的数组,您可以通过以下方式对其进行转换:

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

在 ES6 中:

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

但由于扩展语法,您现在很少直接使用arguments 对象。

【讨论】:

谢谢,应用可以解决问题,在这种情况下调用不起作用。是不是写错了? 如果函数实际上是一个类的成员,你会怎么做?这是正确的吗? theObject.member.apply(theObject, arguments); Array.prototype.slice.call(arguments); 阻止像 V8 这样的浏览器 JS 优化。 Details here 1. 显然,arguments 计划被弃用以支持the spread operator。我没有这方面的消息来源,但我在某处听说过。 2. MDN states 在 arguments 对象上使用 slice 会阻止 V8 等引擎的优化。他们建议使用“被鄙视的数组构造函数”Array.from(arguments)[...arguments]。您愿意更新您对 ES2015 的答案吗? 注意:我继续写了my own answer。【参考方案2】:

实际上,您可以向任何 javascript 函数传递任意数量的值。显式命名的参数将获取前几个值,但所有参数都将存储在 arguments 数组中。

要以“解包”形式传递参数数组,您可以使用 apply,如下所示(c.f. 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);

【讨论】:

【参考方案3】:

apply 函数有两个参数;对象this 将被绑定到,参数用数组表示。

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

【讨论】:

【参考方案4】:

它被称为splat 运算符。你可以在 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); 

【讨论】:

【参考方案5】:

对于那些从Passing variable number of arguments from one function to another 被重定向到这里的人(应该被标记为这个问题的重复):

如果您尝试将可变数量的参数从一个函数传递给另一个函数,从 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".

注意:第一个参数是要使用的this 参数。传递null 将从全局上下文中调用函数,即作为全局函数而不是某个对象的方法。

根据this document,ECMAScript 5 规范重新定义了apply() 方法以采用任何“通用类数组对象”,而不是严格意义上的数组。因此,您可以直接将arguments 列表传递给第二个函数。

在 Chrome 28.0、Safari 6.0.5 和 IE 10 中测试。请使用 this JSFiddle 试用。

【讨论】:

【参考方案6】:

splat 和 spread 运算符是 ES6 的一部分,ES6 是计划的下一个 Javascript 版本。到目前为止,只有 Firefox 支持它们。此代码适用于 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');

注意传播的尴尬语法。 sprintf('The %s %s fox jumps over the %s dog.', ...arr); 的常用语法是 not yet supported。你可以找到an ES6 compatibility table here。

还要注意 for...of 的使用,这是 ES6 的另一个补充。对数组使用for...in 是a bad idea。

【讨论】:

Firefox 和 Chrome 支持正常的传播语法【参考方案7】:
(function(window) 
  var proxied = window.alert;
  window.alert = function() 
    return proxied.apply(window, arguments);
  ;
(this));

alert(13, 37);

【讨论】:

【参考方案8】:

这是一个示例程序,用于计算变量参数和整数数组的整数之和。希望这会有所帮助。

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);

【讨论】:

一些注意事项: 1. var 声明了一个function scope 变量。新的 letconst 关键字 (ES 2015) 声明了 block scope 变量。但是,在 ES 2015 之前,作为实践,变量应该仍然被提升到函数的顶部。 2. 当给定 1 个整数值时,您的函数会中断,因为您错误地接受了数组作为参数(问题是关于 varargs;不接受数组作为参数):CalculateSum(6) -&gt; 0。 (在下一篇文章中继续) 3.不要使用像alert 这样的调试函数。实际上,只是不要使用alert/prompt/confirm,句号。调试时请改用console.log。 4.函数应该是returning一个值,而不是alerting它。 5. 避免PascalCase,除非它指的是一种“类型”的数据。 IE。一类。请改用camelCaseunder_score。 4. 我不喜欢你声明函数的方式。 var f = function() ... 暗示您希望它在某个时候更改,这可能不是您的意图。请改用传统的function name() ... 语法。 为了证明所有这些批评点,here is an improved version 你的答案中的函数。【参考方案9】:

从 ES2015 开始有两种方法。

The arguments Object

此对象内置于函数中,它恰当地引用了函数的参数。但是,从技术上讲,它不是一个数组,因此典型的数组操作无法在它上面工作。建议的方法是使用Array.from 或扩展运算符从中创建一个数组。

我看到其他答案提到使用slice。不要那样做。它会阻止优化(来源:MDN)。

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

但是,我认为arguments 是有问题的,因为它隐藏了函数接受作为输入的内容。 arguments 函数通常是这样写的:

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

有时,函数头的写法如下,以类似 C 的方式记录参数:

function mean(/* ... */) ... 

但这很少见。

至于为什么会出现问题,以 C 为例。 C 向后兼容一种古老的 pre-ANSI 方言,称为 K&R C。K&R C 允许函数原型有一个空参数列表。

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

ANSI C 为varargs (...) 和void 提供了一种指定空参数列表的工具。

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

许多人无意中用unspecified 参数列表(int myfunction();) 声明函数,而他们希望函数接受零参数。这在技术上是一个错误,因为函数 接受参数。任意数量。

C 中一个适当的varargs 函数采用以下形式:

int myFunction(int nargs, ...);

而 JavaScript 实际上也有类似的东西。

Spread Operator / Rest Parameters

实际上,我已经向您展示了展开运算符。

...name

它非常通用,也可以在函数的参数列表(“其余参数”)中使用,以一种有据可查的方式指定可变参数:

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

或作为 lambda 表达式:

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

我更喜欢扩展运算符。它是干净的和自我记录的。

【讨论】:

感谢您提供更新的答案,这篇文章早于 ES 2015,所以我很高兴您填写了更新的选项【参考方案10】:

是的,您可以传递变量编号。函数的参数。您可以使用apply 来实现此目的。

例如:

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

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


applyTest.apply(null,arr);

【讨论】:

【参考方案11】:

在 ES6 中,您可以将 rest parameters 用于 varagrs。这需要参数列表并将其转换为数组。

function logArgs(...args) 
    console.log(args.length)
    for(let arg of args) 
        console.log(arg)
    

【讨论】:

【参考方案12】:

您希望您的函数对数组参数或变量参数做出反应吗?如果是后者,请尝试:

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));
;

但是如果你想处理一个数组参数

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

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

【讨论】:

以上是关于是否可以向 JavaScript 函数发送可变数量的参数?的主要内容,如果未能解决你的问题,请参考以下文章

轻松学习 JavaScript——第 2 部分:函数中的 Rest 参数

在一个用户段中,FCM可以向其发送通知的设备是否有限制?

arguments对象与Rest参数

如何向 javascript 的 fetch() 函数发送附加数据

在excel中生成可变数量工作表的PDF并通过电子邮件发送

是否可以创建具有可变数量元素的数组?