¿Existe un número máximo de argumentos que las funciones de JavaScript pueden aceptar?

80

Sé que las funciones de JavaScript pueden aceptar "cualquier" número de argumentos.

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

Pero me pregunto si realmente hay un límite para cuántos "cualquiera" puede haber.

Por ejemplo, digamos que le entrego un millón de argumentos f(). Funcionaría eso? ¿O el intérprete se derrumbaría?

Supongo que el máximo es (a) específico de la implementación o (b) (2^32)-1, ya que el argumentsobjeto es similar a una matriz.

No veo que esto se mencione en la especificación del idioma, pero es posible que no esté conectando algunos puntos.

GladstoneMantener
fuente
3
Además, CUALQUIER secuencia grande de datos como esta debe pasarse como un solo argumento que es una matriz, no como argumentos separados, por lo que no es necesario hacer una copia completa del conjunto de datos grande solo para llamar a la función. Este tiene que ser un ejercicio académico, no algo que se encontraría con buenas prácticas de desarrollo.
jfriend00
1
@ jfriend00, no te olvides Function.prototype.apply. stackoverflow.com/questions/1379553/…
Paul Draper
@PaulDraper: lo sé .apply(), pero también está haciendo una copia de la matriz de entrada. El punto es que cualquier interfaz que espere aceptar una gran cantidad de argumentos no debe declararse para requerir que se pasen como argumentos normales. Es mucho más eficiente pasar una matriz, por lo que no es necesario realizar una copia de los datos.
jfriend00
5
@ IngoBürk ¡Esta no es una pregunta teórica! Incluso si nunca escribe explícitamente dicha función, si usa el operador de extensión ES 2015 y funciones como Math.maxo Array.prototype.concat(...arrayOfArrays)(para aplanar una matriz de matrices), puede llegar a ese límite de forma dinámica, sin haber escrito una función monstruosa. La sobrecarga mencionada por jfriend00 no siempre importa: la claridad del código es más importante que unos pocos bytes de memoria o ciclos de CPU, y la sintaxis extendida a veces puede ser la mejor opción en ese sentido. Busque alternativas para "aplanar matriz" para mi código corto ...
Mörre
@ Mörre Mi comentario es de marzo de 2014. ES5015 no se publicó hasta junio de 2015.
Ingo Bürk

Respuestas:

92

Aunque no hay nada específico que limite el número máximo teórico de argumentos en la especificación (como señala la respuesta de thefortheye ). Por supuesto, existen límites prácticos . Estos límites dependen completamente de la implementación y, muy probablemente, también dependerán exactamente de cómo llame a la función.


He creado este violín como un experimento.

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

Aquí están mis resultados:

  • Chrome 33.0.1750.154 m: la última prueba exitosa fue 65535 argumentos. Después de eso falló con:

    RangeError no detectado: se excedió el tamaño máximo de la pila de llamadas

  • Firefox 27.0.1: la última prueba exitosa fue 262143 argumentos. Después de eso falló con:

    RangeError: la matriz de argumentos pasada a Function.prototype.apply es demasiado grande

  • Internet Explorer 11: la última prueba satisfactoria fue 131071 argumentos. Después de eso falló con:

    RangeError: SCRIPT28: Fuera de espacio de pila

  • Opera 12.17: La última prueba exitosa fue 1048576 argumentos. Después de eso falló con:

    Error: Function.prototype.apply: argArray es demasiado grande

Por supuesto, puede haber otros factores en juego aquí y es posible que obtenga resultados diferentes.


Y aquí hay un violín alternativo creado con eval. Nuevamente, puede obtener resultados diferentes.

  • Chrome 33.0.1750.154 m: la última prueba exitosa fue 32767 argumentos. Después de eso falló con:

    Error de sintaxis no detectado: demasiados argumentos en la llamada a la función (solo se permite 32766)

    Este es particularmente interesante porque el propio Chrome parece estar confundido acerca de cuántos argumentos se permiten realmente.

  • Firefox 27.0.1: la última prueba exitosa fue 32767 argumentos. Después de eso falló con:

    script demasiado grande

  • Internet Explorer 11: la última prueba satisfactoria fue 32767 argumentos. Después de eso falló con:

    RangeError: SCRIPT7: Memoria insuficiente

  • Opera 12.17: La última prueba exitosa fue 4194303 argumentos. Después de eso falló con:

    Sin memoria; script terminado.

pswg
fuente
Esto es genial. Aunque si está utilizando applyy enviando argumentos como un Array, el máximo teórico según la especificación sería 4,294,967,295 elementos sin importar cuáles sean los límites prácticos (?).
Gladstone
1
Su ejemplo está probando el máximo de .apply()más argumentos de función pasados ​​como se muestra en la pregunta. No son necesariamente iguales. Aquí hay una demostración en la que he creado una función a partir de una cadena utilizando el Functionconstructor. La función invoca su testArgs()función, pasándole 100.000 argumentos. Simplemente crear esa función falla conSyntaxError: too many function arguments
cookie monster
@cookiemonster Tienes razón. Hay muchos factores diferentes que pueden limitar el número máximo y diferentes métodos para llamarlo pueden producir resultados diferentes. Supongo que debería enfatizar un poco más la primera oración.
pswg
Sí, todo depende de lo que tenga en mente el OP. No puedo imaginarme escribiendo 100.000 argumentos en una función, por .apply()lo que parece más probable. Pero luego no lo mencionó .apply(), así que tal vez esté planeando hacer algo eval.
monstruo de las galletas
@GladstoneMantener correcto. Mis pruebas tratan de averiguar los límites prácticos aproximados en un navegador determinado.
pswg
22

ECMAScript 5.1, parte 8.8

El tipo Lista se utiliza para explicar la evaluación de listas de argumentos (ver 11.2.4) en nuevas expresiones, en llamadas a funciones y en otros algoritmos donde se necesita una lista simple de valores ... Estas secuencias pueden tener cualquier longitud.

Entonces no hay límite en el estándar. Por supuesto, si su código se ejecuta en el mundo real, no en la tierra de los estándares, obviamente hay algún límite (por ejemplo, el número de partículas en el universo).

Hay dos formas de pasar parámetros a una función.

  • "Literalmente": f(a, b, c)
  • Con aplicar (): f.apply(null, [a, b, c])

Esta última forma es el escenario más realista para grandes listas de argumentos.

Vaya a este JSFiddle para ver los límites de cada uno de estos para su navegador actual.

Yo mismo probé algunos navegadores:

           | 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

Vi diferencias en muchos de estos números en diferentes máquinas, así que creo que hay otros factores en juego además del navegador (¿el sistema operativo?).


Este es un problema real, no una trivia. Un ejemplo del mundo real:

La biblioteca de cierre de Google definió la siguiente función.

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

Esto funcionó solo si la longitud de la cadena estaba dentro del límite del navegador para la cantidad de argumentos que se pueden pasar Function.prototype.apply.

La función se parcheó más tarde , lo que la hizo mucho más complicada.


Para su información, hay un problema de Webkit abierto presentado en marzo de 2012 que analiza el límite de argumentos.

Paul Draper
fuente
6

De acuerdo con la Especificación Estándar ECMA Script 5.1 paraList ,

El tipo Lista se utiliza para explicar la evaluación de listas de argumentos (ver 11.2.4) en nuevas expresiones, en llamadas a funciones y en otros algoritmos donde se necesita una lista simple de valores. Los valores del tipo Lista son simplemente secuencias de valores ordenadas. Estas secuencias pueden tener cualquier longitud.

Entonces, el estándar no tiene limitaciones en el número de argumentos y solo está limitado por la memoria.

los cuatro ojos
fuente
2

Estupideces informáticas
> de Computer Stupidities

En lo que a mí respecta, ¡el límite es "suficientemente grande"!

Niet the Dark Absol
fuente
6
"¡el límite es 'suficientemente grande'!" A menos que no lo sea. bugs.webkit.org/show_bug.cgi?id=80797
Paul Draper
1

Depende puramente de cuán poderoso sea el cliente.

Porque el navegador perderá su memoria, si vas a pasar millones de argumentos.

Cada variable tiene algo de memoria. Por lo tanto, los navegadores no tendrán problemas para asignar algo de memoria a cada variable, hasta que no tenga memoria para ejecutarse.

Amit Joki
fuente
1

Simplemente use un mapa (solo un objeto) como un solo parámetro. Aún puede usar nombres de parámetros y puede tener tantos argumentos como desee. Le garantiza un número teórico infinito de argumentos que puede pasar, sin embargo, obviamente, aún permanece limitado por el espacio del montón.

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

infiniteParameters({
  name1 : "value1",
  name2 : "value2",
  // ...
});
Mark Russell
fuente
0

Así es como lo compruebo.

let args = [];

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