JavaScript函数可以接受的参数数量上限吗?


79

我知道JavaScript函数可以接受“任意”数量的参数。

function f(){};
f(1,2,3,4 /*...*/);

但是我想知道实际上有多少个“任何”个数是否有限制?

例如,假设我向提出了一百万个论点f()。那行得通吗?还是口译员会弯腰?

我猜测最大值是(a)特定于实现的(b)(2^32)-1,因为arguments对象是类似数组的。

我在语言规范中没有看到这一点,但是我可能没有连接一些点。


30
我真的希望这纯粹是出于好奇,而不是因为您打算对此做任何事情。
IngoBürk2014年

3
另外,任何像这样的大数据序列都应作为数组的单个参数传递,而不是作为单独的参数传递,因此不必为调用函数而对大型数据集进行整个复制。这必须是一项学术活动,而不是良好的开发实践会遇到的事情。
jfriend00 2014年

1
@IngoBürk是的,只是出于好奇:-)
GladstoneKeep

1
@ jfriend00,不要忘记Function.prototype.applystackoverflow.com/questions/1379553/…–
保罗·德雷珀

5
@IngoBürk这不是理论问题!即使您从未明确编写过这样的函数,如果您使用ES 2015扩展运算符和类似Math.max或的函数Array.prototype.concat(...arrayOfArrays)(或展平数组的数组),也可以动态达到该限制,而无需编写monster函数。jfriend00提到的开销并不总是很重要-代码的清晰性比几个字节的内存或CPU周期更为重要,在这方面,扩展语法有时可能是最佳选择。看看在“扁平化阵列”替代我的短代码...
Mörre

Answers:


92

尽管没有具体限制规范中参数的理论最大数量(如thefortheye的答案所 指出)。当然有实际的限制。这些限制是完全依赖于实现的,最有可能,也将取决于究竟在如何你调用的函数。


我创建了这个小提琴作为实验。

function testArgs() {
    console.log(arguments.length);
}

var argLen = 0;
for (var i = 1; i < 32; i++) {
    argLen = (argLen << 1) + 1;
    testArgs.apply(null, new Array(argLen));
}

这是我的结果:

  • Chrome 33.0.1750.154 m:最近一次成功的测试是65535个自变量。之后,它失败并显示:

    未捕获的RangeError:超出最大调用堆栈大小

  • Firefox 27.0.1:最近一次成功的测试是262143个参数。之后,它失败并显示:

    RangeError:传递给Function.prototype.apply的arguments数组太大

  • Internet Explorer 11:上一次成功的测试是131071自变量。之后,它失败并显示:

    RangeError:SCRIPT28:堆栈空间不足

  • Opera 12.17:最近一次成功的测试是1048576自变量。之后,它失败并显示:

    错误:Function.prototype.apply:argArray太大

当然,这里可能还有其他因素,您可能会有不同的结果。


这是使用创建的替代提琴eval。同样,您可能会得到不同的结果。

  • Chrome 33.0.1750.154 m:最近一次成功的测试是32767个参数。之后,它失败并显示:

    未捕获的SyntaxError:函数调用中的参数过多(仅允许32766)

    这一点特别有趣,因为Chrome本身似乎对实际上允许多少个参数感到困惑。

  • Firefox 27.0.1:最近一次成功的测试是32767个参数。之后,它失败并显示:

    脚本太大

  • Internet Explorer 11:上一次成功的测试是32767个参数。之后,它失败并显示:

    RangeError:SCRIPT7:内存不足

  • Opera 12.17:最近一次成功的测试是4194303自变量。之后,它失败并显示:

    记不清; 脚本已终止。


这很棒。尽管如果您使用apply参数并以形式发送参数Array,则无论实际限制是多少(?),每个规范的理论最大值为4,294,967,295个元素。
GladstoneKeep'Mar

1
您的示例正在测试.apply()问题中传递的超过函数参数的最大值。它们不一定相同。这是一个演示,其中我使用Function构造函数从字符串创建了一个函数。该函数调用您的testArgs()函数,并为其传递100,000个参数。仅仅创建该函数失败SyntaxError: too many function arguments
Cookie怪物

@cookiemonster你是对的。有许多不同的因素可能会限制最大数量,并且调用它的不同方法可能会产生不同的结果。我想我应该再强调第一句话。
pswg

是的,这完全取决于OP的想法。我无法想象为一个函数键入100,000个参数,因此.apply()似乎更有可能。但是后来他没有提及.apply(),所以也许他正计划做些事情eval
Cookie怪物

@GladstoneKeep正确。我的测试是要找出给定浏览器中的近似实际限制。
pswg

22

ECMAScript 5.1,第8.8部分

List类型用于解释新表达式,函数调用以及其他需要简单值列表的算法中对参数列表(请参见11.2.4)的求值。这些序列可以是任意长度。

因此,该标准没有限制。当然,如果您的代码在现实世界中运行,而不是在标准地区运行,则显然存在一些限制(例如,宇宙中的粒子数量)。

有两种方法可以将参数传递给函数。

  • “从字面上看”: f(a, b, c)
  • 使用apply(): f.apply(null, [a, b, c])

对于大型参数列表,后一种方式是更实际的方案。

转到此JSFiddle,以查看当前浏览器的每个限制。

我自己尝试了几种浏览器:

           | apply() | literal
 ----------------------------
Chrome 14  | 131155  |  32767
Chrome 35  | 126213  |  65535
Firefox 30 | 500001  |  65535
IE 9       | 254335  |  65533
IE 10      | 253667  |  65533
IE 11      | 252447  |  65533
Opera 22   | 126063  |  65535
Safari 4   | 524215  | 524205
Safari 7   |  65537  | 522159

我在不同的机器上看到了许多数字上的差异,所以我相信除了浏览器(操作系统?)之外,还有其他因素在起作用。


这是一个实际问题,而不是琐事。一个真实的例子:

Google Closure库定义了以下功能。

goog.crypt.byteArrayToString = function(array) {
  return String.fromCharCode.apply(null, array);
};

仅当字符串的长度在浏览器的可传递参数范围之内时,此方法才有效Function.prototype.apply

后来对该功能进行了修补,从而使该功能更加复杂。


仅供参考,2012年3月提交了一个公开的Webkit问题,讨论了参数限制。


6

根据ECMA脚本5.1标准规范List

List类型用于解释在新表达式,函数调用以及需要简单值列表的其他算法中对参数列表(请参见11.2.4)的求值。List类型的值只是值的有序序列。这些序列可以是任何长度。

因此,该标准对参数的数量没有任何限制,仅受内存限制。



1

它完全取决于客户端的功能。

因为浏览器将失去记忆,所以如果您要传递数百万个参数。

每个变量都保存一些内存。因此,浏览器将不会为每个变量分配一些内存,直到它本身没有可运行的内存为止。


1

只需将地图(只是一个对象)用作单个参数即可。您仍然可以使用参数名称,并且可以根据需要使用任意数量的参数。它保证了您可以传入的理论上无限数量的参数,但是显然您仍然受到堆空间的限制。

let infiniteParameters = (w) => console.table(w);

infiniteParameters({
  name1 : "value1",
  name2 : "value2",
  // ...
});

0

这是我的检查方法。

let args = [];

while(true){
    try{
        (() => {})(...args);
        args.push(0);
    }catch(e){
        console.log(e.message);
        console.log(`Number of arguments: ${args.length}`);
        break;
    }
}

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.