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

Fir*_*row 159 javascript variadic-functions

是否可以从数组中向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'
Run Code Online (Sandbox Code Playgroud)

我最近写了很多Python,这是一个很好的模式,能够接受varargs并发送它们.例如

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'
Run Code Online (Sandbox Code Playgroud)

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

CMS*_*CMS 182

使用申请:

func(...arr);
Run Code Online (Sandbox Code Playgroud)

请注意,apply它用作apply的第一个参数,它将this关键字设置为内部的Global对象(窗口)apply.

另请注意,该this对象实际上不是一个数组,您可以通过以下方式对其进行转换:

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

const values = ['a', 'b', 'c']
func(...values)
func(1, 2, 3)
Run Code Online (Sandbox Code Playgroud)

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

function func(first, second, ...theRest) {
  //...
}
Run Code Online (Sandbox Code Playgroud)

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

  • `Array.prototype.slice.call(arguments);`阻止像V8这样的浏览器JS优化.[详细信息](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/arguments) (4认同)
  • **1.**显然,'arguments`计划被弃用,以支持[传播运算符](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_operator ).我没有这方面的来源,但我在某个地方听到了.**2. [MDN状态](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/arguments)在`arguments`对象上使用`slice`会阻止优化在像V8这样的引擎中.他们建议使用"despised Array构造函数","Array.from(arguments)`或`[... arguments]`.您是否愿意更新ES2015的答案? (2认同)

dan*_*ben 73

您实际上可以将任意数量的值传递给任何javascript函数.显式命名的参数将获得前几个值,但ALL参数将存储在arguments数组中.

要以"unpacked"形式传递arguments数组,您可以像使用apply一样使用apply(cf 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);
Run Code Online (Sandbox Code Playgroud)


Tgr*_*Tgr 22

图示传播运营商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');
Run Code Online (Sandbox Code Playgroud)

注意传播的awkard语法.常用的语法的sprintf('The %s %s fox jumps over the %s dog.', ...arr);还不支持.您可以在此处找到ES6兼容性表.

for...of另请注意另外ES6 的使用.使用for...in数组是一个坏主意.


Bra*_*est 8

ES2015有两种方法.

arguments对象

该对象内置于函数中,它适当地引用函数的参数.但是,从技术上讲,它不是一个数组,所以典型的数组操作不适用于它.建议的方法是使用Array.from或扩展运算符从中创建数组.

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

Array.from(arguments)
[...arguments]
Run Code Online (Sandbox Code Playgroud)

但是,我认为这arguments是有问题的,因为它隐藏了函数接受的输入.一个arguments功能通常是这样写的:

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

有时,函数头像下面这样编写,以类似C的方式记录参数:

function mean(/* ... */){ ... }
Run Code Online (Sandbox Code Playgroud)

但这种情况很少见.

至于为什么它有问题,以C为例.C向后兼容一种称为K&R C的古老的ANSI前语言.K&R C允许函数原型具有空参数列表.

int myFunction();
/* This function accepts unspecified parameters */
Run Code Online (Sandbox Code Playgroud)

ANSI C为varargs(...)提供了一个工具,并void指定了一个空参数列表.

int myFunction(void);
/* This function accepts no parameters */
Run Code Online (Sandbox Code Playgroud)

许多人无意中使用unspecified参数list(int myfunction();)声明函数,当他们期望函数采用零参数时.这在技术上是一个错误,因为该函数接受参数.任意数量的.

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

int myFunction(int nargs, ...);
Run Code Online (Sandbox Code Playgroud)

JavaScript实际上确实有类似的东西.

传播操作员/休息参数

实际上,我已经向你展示了传播运营商.

...name
Run Code Online (Sandbox Code Playgroud)

它非常通用,也可以在函数的参数列表("休息参数")中使用,以一种很好的文档方式指定varargs:

function mean(...args){
    return args.reduce((a,b)=>a+b) / args.length;
}
Run Code Online (Sandbox Code Playgroud)

或者作为lambda表达式:

((...args)=>args.reduce((a,b)=>a+b) / args.length)(1,2,3,4,5); // 3
Run Code Online (Sandbox Code Playgroud)

我更喜欢传播运营商.它干净,自我记录.

  • 谢谢你的更新答案,这篇文章早于ES 2015,所以我很高兴你填写了最近的选项 (2认同)

Aug*_*aas 7

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

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


Cha*_*tni 5

它被称为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); 
Run Code Online (Sandbox Code Playgroud)