Gibt es eine maximale Anzahl von Argumenten, die JavaScript-Funktionen akzeptieren können?

79

Ich weiß, dass JavaScript-Funktionen "beliebig" viele Argumente akzeptieren können.

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

Aber ich frage mich, ob es tatsächlich eine Grenze gibt, wie viele "irgendwelche" sein können?

Nehmen wir zum Beispiel an, ich übergebe eine Million Argumente f(). Funktioniert das? Oder würde der Dolmetscher umkippen?

Ich vermute, das Maximum ist entweder (a) implementierungsspezifisch oder (b) (2^32)-1, da das argumentsObjekt Array-ähnlich ist.

Ich sehe dies nicht in der Sprachspezifikation erwähnt, aber ich kann einige Punkte nicht verbinden.

GladstoneKeep
quelle
30
Ich hoffe wirklich, dass dies nur aus Neugier geschieht, nicht weil Sie vorhaben, etwas damit zu tun.
Ingo Bürk
3
Außerdem sollte JEDE große Datenfolge wie diese als einzelnes Argument übergeben werden, das ein Array ist, und nicht als separate Argumente, sodass nicht eine vollständige Kopie des großen Datensatzes erstellt werden muss, nur um die Funktion aufzurufen. Dies muss eine akademische Übung sein, die bei guten Entwicklungspraktiken nicht anzutreffen ist.
jfriend00
1
@ IngoBürk Ja, nur aus Neugier :-)
GladstoneKeep
1
@ jfriend00, vergiss nicht Function.prototype.apply. stackoverflow.com/questions/1379553/…
Paul Draper
5
@ IngoBürk Dies ist keine theoretische Frage! Selbst wenn Sie eine solche Funktion niemals explizit schreiben, können Sie mit dem ES 2015-Spread-Operator und Funktionen wie Math.maxoder Array.prototype.concat(...arrayOfArrays)(um ein Array von Arrays zu reduzieren) dynamisch an diese Grenze gelangen, ohne eine Monsterfunktion geschrieben zu haben. Der von jfriend00 erwähnte Overhead spielt nicht immer eine Rolle - die Klarheit des Codes ist wichtiger als ein paar Bytes Speicher oder CPU-Zyklen, und die Spread-Syntax ist in dieser Hinsicht manchmal die beste Wahl. Schauen Sie sich Alternativen für "Array reduzieren" zu meinem Funktionscode an ...
Mörre

Antworten:

92

Obwohl es nichts Spezifisches gibt, das die theoretische maximale Anzahl von Argumenten in der Spezifikation einschränkt (wie die Antwort von thefortheye hervorhebt ). Es gibt natürlich praktische Grenzen. Diese Grenzwerte sind vollständig implementierungsabhängig und hängen höchstwahrscheinlich auch genau davon ab, wie Sie die Funktion aufrufen.


Ich habe diese Geige als Experiment erstellt.

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

Hier sind meine Ergebnisse:

  • Chrome 33.0.1750.154 m: Der letzte erfolgreiche Test bestand aus 65535 Argumenten. Danach schlug es fehl mit:

    Nicht erfasster RangeError: Maximale Aufrufstapelgröße überschritten

  • Firefox 27.0.1: Der letzte erfolgreiche Test bestand aus 262143 Argumenten. Danach schlug es fehl mit:

    RangeError: Das an Function.prototype.apply übergebene Argumentarray ist zu groß

  • Internet Explorer 11: Der letzte erfolgreiche Test bestand aus 131071 Argumenten. Danach schlug es fehl mit:

    RangeError: SCRIPT28: Nicht genügend Stapelspeicher

  • Opera 12.17: Der letzte erfolgreiche Test bestand aus 1048576 Argumenten. Danach schlug es fehl mit:

    Fehler: Function.prototype.apply: argArray ist zu groß

Natürlich können hier andere Faktoren eine Rolle spielen und Sie können unterschiedliche Ergebnisse erzielen.


Und hier ist eine alternative Geige, die mit erstellt wurde eval. Auch hier können unterschiedliche Ergebnisse erzielt werden.

  • Chrome 33.0.1750.154 m: Der letzte erfolgreiche Test bestand aus 32767 Argumenten. Danach schlug es fehl mit:

    Nicht erfasster SyntaxError: Zu viele Argumente im Funktionsaufruf (nur 32766 zulässig)

    Dieser ist besonders interessant, da Chrome selbst verwirrt darüber zu sein scheint, wie viele Argumente tatsächlich zulässig sind.

  • Firefox 27.0.1: Der letzte erfolgreiche Test bestand aus 32767 Argumenten. Danach schlug es fehl mit:

    Skript zu groß

  • Internet Explorer 11: Der letzte erfolgreiche Test bestand aus 32767 Argumenten. Danach schlug es fehl mit:

    RangeError: SCRIPT7: Nicht genügend Speicher

  • Opera 12.17: Der letzte erfolgreiche Test bestand aus 4194303 Argumenten. Danach schlug es fehl mit:

    Nicht genügend Speicher; Skript beendet.

pswg
quelle
Das ist toll. Wenn Sie applyArgumente als verwenden und senden Array, beträgt das theoretische Maximum pro Spezifikation 4.294.967.295 Elemente, unabhängig von den praktischen Grenzen (?).
GladstoneKeep
1
In Ihrem Beispiel wird das Maximum von .apply()mehr als Funktionsargumenten getestet, die wie in der Frage gezeigt übergeben wurden. Sie sind nicht unbedingt gleich. Hier ist eine Demo, in der ich mit dem FunctionKonstruktor eine Funktion aus einer Zeichenfolge erstellt habe . Die Funktion ruft Ihre testArgs()Funktion auf und übergibt ihr 100.000 Argumente. Das bloße Erstellen dieser Funktion schlägt mitSyntaxError: too many function arguments
Cookie Monster
@cookiemonster Du bist richtig. Es gibt viele verschiedene Faktoren, die die maximale Anzahl begrenzen können, und verschiedene Methoden zum Aufrufen können zu unterschiedlichen Ergebnissen führen. Ich denke, ich sollte den ersten Satz etwas mehr betonen.
Pswg
Ja, es hängt alles davon ab, was das OP vorhat. Ich kann mir nicht vorstellen, 100.000 Argumente für eine Funktion einzugeben, daher .apply()scheint dies wahrscheinlicher. Aber dann hat er es nicht erwähnt .apply(), also hat er vielleicht vor, etwas zu tun eval.
Cookie Monster
@GladstoneKeep Richtig. Bei meinen Tests geht es darum, die ungefähren praktischen Grenzen in einem bestimmten Browser herauszufinden .
Pswg
22

ECMAScript 5.1, Teil 8.8

Der Listentyp wird verwendet, um die Auswertung von Argumentlisten (siehe 11.2.4) in neuen Ausdrücken, in Funktionsaufrufen und in anderen Algorithmen zu erläutern, bei denen eine einfache Werteliste erforderlich ist. Diese Sequenzen können beliebig lang sein.

Der Standard kennt also keine Grenzen. Wenn Ihr Code in der realen Welt und nicht im Standardland ausgeführt wird, gibt es natürlich eine gewisse Grenze (z. B. Anzahl der Partikel im Universum).

Es gibt zwei Möglichkeiten, Parameter an eine Funktion zu übergeben.

  • "Buchstäblich": f(a, b, c)
  • Mit apply (): f.apply(null, [a, b, c])

Dieser letztere Weg ist das realistischere Szenario für große Argumentlisten.

Gehen Sie zu dieser JSFiddle , um die jeweiligen Grenzwerte für Ihren aktuellen Browser anzuzeigen .

Ich habe selbst ein paar Browser ausprobiert:

           | 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

Ich habe Unterschiede in vielen dieser Zahlen auf verschiedenen Computern gesehen, daher glaube ich, dass neben dem Browser (dem Betriebssystem?) Andere Faktoren eine Rolle spielen.


Dies ist ein echtes Problem, keine Trivia. Ein Beispiel aus der Praxis:

Die Google Closure Library hat die folgende Funktion definiert.

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

Dies funktionierte nur, wenn die Länge der Zeichenfolge innerhalb des Browserlimits für die Anzahl der Argumente lag, mit denen übergeben werden kann Function.prototype.apply.

Die Funktion wurde später gepatcht , was die Funktion erheblich komplizierter machte.


Zu Ihrer Information, im März 2012 wurde ein offenes Webkit-Problem eingereicht, in dem die Argumentationsgrenze erörtert wird.

Paul Draper
quelle
6

Gemäß ECMA Script 5.1 Standardspezifikation fürList ,

Der Listentyp wird verwendet, um die Auswertung von Argumentlisten (siehe 11.2.4) in neuen Ausdrücken, in Funktionsaufrufen und in anderen Algorithmen zu erläutern, bei denen eine einfache Werteliste erforderlich ist. Werte vom Typ Liste sind einfach geordnete Wertesequenzen. Diese Sequenzen können beliebig lang sein.

Der Standard hat also keine Einschränkungen hinsichtlich der Anzahl der Argumente und ist nur durch den Speicher begrenzt.

thefourtheye
quelle
2

Computer Dummheiten
> von Computer-Dummheiten

Für mich ist das Limit "groß genug"!

Niet the Dark Absol
quelle
6
"Das Limit ist 'groß genug'!" Es sei denn, es ist nicht. bugs.webkit.org/show_bug.cgi?id=80797
Paul Draper
1

Es hängt nur davon ab, wie mächtig der Client ist.

Weil der Browser seinen Speicher verliert, wenn Sie Millionen von Argumenten übergeben.

Jede Variable enthält etwas Speicher. Browser haben also kein Problem damit, jeder Variablen Speicher zuzuweisen, bis sie selbst keinen Speicher mehr hat, auf dem sie ausgeführt werden kann.

Amit Joki
quelle
1

Verwenden Sie einfach eine Karte (nur ein Objekt) als einzelnen Parameter. Sie können weiterhin Parameternamen verwenden und können so viele Argumente haben, wie Sie möchten. Es garantiert Ihnen eine theoretisch unendliche Anzahl von Argumenten, die Sie übergeben können, aber Sie bleiben offensichtlich immer noch vom Heap-Speicherplatz begrenzt.

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

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

Hier ist, wie ich es überprüfe.

let args = [];

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