JavaScript-Variable Anzahl der zu funktionierenden Argumente

531

Gibt es eine Möglichkeit, "unbegrenzte" Variablen für eine Funktion in JavaScript zuzulassen?

Beispiel:

load(var1, var2, var3, var4, var5, etc...)
load(var1)
Timo
quelle
verwandtes / mögliches Duplikat von stackoverflow.com/questions/4633125/…
Luke
1
@ Luke nein, ist es nicht. In dieser Frage wird gefragt, wie eine Funktion mit einer beliebigen Anzahl von Argumenten mit den Argumenten in einem Array aufgerufen werden soll. Hier wird gefragt, wie ein solcher Anruf behandelt werden soll.
Scruffy
1
Zur einfacheren Suche wird eine solche Funktion als "variable Funktion" bezeichnet.
Gschenk

Antworten:

814

Sicher, benutze einfach das argumentsObjekt.

function foo() {
  for (var i = 0; i < arguments.length; i++) {
    console.log(arguments[i]);
  }
}
roufamatisch
quelle
1
Tnx. Es eignet sich hervorragend zum Parsen von Strings von nativem Android-Code zu Javascript in einer Webansicht.
Johan Hoeksma
4
Diese Lösung hat bei mir am besten funktioniert. Vielen Dank. Weitere Informationen zum Argument-Schlüsselwort HIER .
User2
26
argumentsist ein spezielles "Array-ähnliches" Objekt, dh es hat eine Länge, aber keine anderen Array-Funktionen. Weitere Informationen finden Sie unter developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/… und diese Antwort: stackoverflow.com/a/13145228/1766230
Luke
4
Interessanterweise wurden die Array-Methoden in Javascript so definiert, dass sie für jedes Objekt mit einer lengthEigenschaft funktionieren . Dies schließt das argumentsObjekt ein. Dies und das wissen die Methodeconcat wir eine Kopie des aufgerufenen 'Arrays' zurückgibt , können wir das argumentsObjekt leicht in ein reales Array wie das folgende konvertieren : var args = [].concat.call(arguments). Einige Leute bevorzugen es Array.prototype.concat.callstattdessen zu verwenden , aber ich mag das [], sie sind kurz und süß!
Stijn de Witt
2
@ YasirJan verwenden[...arguments].join()
Willian D. Andrade
179

In (den meisten) neuesten Browsern können Sie eine variable Anzahl von Argumenten mit folgender Syntax akzeptieren:

function my_log(...args) {
     // args is an Array
     console.log(args);
     // You can pass this array as parameters to another function
     console.log(...args);
}

Hier ist ein kleines Beispiel:

function foo(x, ...args) {
  console.log(x, args, ...args, arguments);
}

foo('a', 'b', 'c', z='d')

=>

a
Array(3) [ "b", "c", "d" ]
b c d
Arguments
    0: "a"
    1: "b"
    2: "c"
    3: "d"
    length: 4

Dokumentation und weitere Beispiele hier: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/rest_parameters

Ramast
quelle
27
Zu
Ihrer Information
4
+1 Dies ist eine elegante und saubere Lösung. Besonders geeignet, um eine lange Liste von Parametern in einen anderen Funktionsaufruf zu übertragen und möglicherweise, dass sich diese variablen Parameter an einer beliebigen Position befinden.
Haxpor
3
Beachten Sie, dass es laut developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/… im IE nicht unterstützt wird.
Roee Gavirel
2
Hier ist eine Tabelle mit Browser-Unterstützung - caniuse.com/#feat=rest-parameters
Brian Burns
1
So eine schöne Antwort!
Ashish
113

Eine andere Möglichkeit besteht darin, Ihre Argumente in einem Kontextobjekt zu übergeben.

function load(context)
{
    // do whatever with context.name, context.address, etc
}

und benutze es so

load({name:'Ken',address:'secret',unused:true})

Dies hat den Vorteil, dass Sie so viele benannte Argumente hinzufügen können, wie Sie möchten, und die Funktion kann sie nach Belieben verwenden (oder nicht).

Ken
quelle
4
Dies wäre besser, da dadurch die Kopplung an die Argumentreihenfolge aufgehoben wird. Locker gekoppelte Schnittstellen sind eine gute Standardpraxis ...
Jonas Schubert Erlandsson
9
Klar, das ist in manchen Fällen besser. Nehmen wir jedoch an, die einzelnen Argumente beziehen sich nicht wirklich aufeinander oder sollen alle die gleiche Bedeutung haben (wie Array-Elemente). Dann ist OPs Weg am besten.
Rvighne
1
Dies ist auch schön, denn wenn Sie möchten, können Sie das contextArgument mit Code erstellen und weitergeben, bevor es verwendet wird.
Nate CK
46

Ich stimme Kens Antwort als die dynamischste zu und gehe noch einen Schritt weiter. Wenn es sich um eine Funktion handelt, die Sie mehrmals mit unterschiedlichen Argumenten aufrufen, verwende ich Kens Design, füge dann aber Standardwerte hinzu:

function load(context) {

    var defaults = {
        parameter1: defaultValue1,
        parameter2: defaultValue2,
        ...
    };

    var context = extend(defaults, context);

    // do stuff
}

Auf diese Weise können Sie, wenn Sie viele Parameter haben, diese aber nicht unbedingt bei jedem Aufruf der Funktion festlegen müssen, einfach die Nicht-Standardwerte angeben. Für die Extend-Methode können Sie die Extend-Methode ( $.extend()) von jQuery verwenden , Ihre eigene erstellen oder Folgendes verwenden:

function extend() {
    for (var i = 1; i < arguments.length; i++)
        for (var key in arguments[i])
            if (arguments[i].hasOwnProperty(key))
                arguments[0][key] = arguments[i][key];
    return arguments[0];
}

Dadurch wird das Kontextobjekt mit den Standardeinstellungen zusammengeführt und alle undefinierten Werte in Ihrem Objekt mit den Standardeinstellungen gefüllt.

mbeasley
quelle
3
+1. Guter Trick. Spart viel Kesselplatte, um jeden Parameter zu definieren, Standard oder auf andere Weise.
Neil
1
Die _.defaults() Methode von Underscore ist eine sehr schöne Alternative zum Zusammenführen angegebener und Standardargumente.
Mbeasley
18

Ja, einfach so:

function load()
{
  var var0 = arguments[0];
  var var1 = arguments[1];
}

load(1,2);
Canavar
quelle
18

Es ist vorzuziehen, die Restparametersyntax zu verwenden, wie Ramast hervorhob.

function (a, b, ...args) {}

Ich möchte nur eine nette Eigenschaft des Arguments ... args hinzufügen

  1. Es ist ein Array und kein Objekt wie Argumente. Auf diese Weise können Sie Funktionen wie Map oder Sort direkt anwenden.
  2. Es enthält nicht alle Parameter, sondern nur den von ihm weitergegebenen. ZB Funktion (a, b, ... args) in diesem Fall enthält args das Argument 3 bis argument.length
Nicola Pedretti
quelle
15

Wie bereits erwähnt, können Sie die verwenden arguments Objekt eine variable Anzahl von Funktionsparametern abrufen.

Wenn Sie eine andere Funktion mit denselben Argumenten aufrufen möchten, verwenden Sie apply. Sie können sogar Argumente hinzufügen oder entfernen, indem Sie sie argumentsin ein Array konvertieren . Diese Funktion fügt beispielsweise Text ein, bevor Sie sich an der Konsole anmelden:

log() {
    let args = Array.prototype.slice.call(arguments);
    args = ['MyObjectName', this.id_].concat(args);
    console.log.apply(console, args);
}
Peter Tseng
quelle
schöne Lösung, um Argumente in Array zu konvertieren. Es war heute hilfreich für mich.
Dmytro Medvid
8

Obwohl ich im Allgemeinen der Meinung bin, dass der Ansatz der benannten Argumente nützlich und flexibel ist (es sei denn, Sie interessieren sich für die Reihenfolge, in welchem ​​Fall Argumente am einfachsten sind), habe ich Bedenken hinsichtlich der Kosten des mbeasley-Ansatzes (unter Verwendung von Standardeinstellungen und Erweiterungen). Dies ist ein extrem hoher Kostenaufwand für das Abrufen von Standardwerten. Zunächst werden die Standardeinstellungen innerhalb der Funktion definiert, sodass sie bei jedem Aufruf neu gefüllt werden. Zweitens können Sie die benannten Werte leicht auslesen und gleichzeitig die Standardeinstellungen mit || festlegen. Es ist nicht erforderlich, ein weiteres neues Objekt zu erstellen und zusammenzuführen, um diese Informationen abzurufen.

function load(context) {
   var parameter1 = context.parameter1 || defaultValue1,
       parameter2 = context.parameter2 || defaultValue2;

   // do stuff
}

Dies ist ungefähr die gleiche Menge an Code (möglicherweise etwas mehr), sollte aber einen Bruchteil der Laufzeitkosten ausmachen.

mcurland
quelle
Einverstanden, obwohl der Schaden von der Art des Wertes oder der Standardeinstellung selbst abhängt. Andernfalls (parameter1=context.parameter1)===undefined && (parameter1=defaultValue1)oder für weniger Codevolumen function def(providedValue, default) {return providedValue !== undefined ? providedValue : defaultValue;} var parameter1 = def(context.parameter1, defaultValue1)bietet eine kleine Hilfsfunktion Folgendes an: Bereitstellung alternativer Muster. Mein Punkt bleibt jedoch bestehen: Das Erstellen zusätzlicher Objekte für jeden Funktionsaufruf und das Ausführen teurer Schleifen zum Festlegen einiger Standardwerte ist ein verrückter Aufwand.
mcurland
7

Während @roufamatic die Verwendung des Argument-Schlüsselworts zeigte und @Ken ein großartiges Beispiel für ein zu verwendendes Objekt zeigte, habe ich das Gefühl, dass weder wirklich angesprochen wurde, was in diesem Fall vor sich geht, noch zukünftige Leser verwirren oder eine schlechte Praxis einflößen könnte, wenn keine Funktion explizit angegeben wird / method soll eine variable Anzahl von Argumenten / Parametern annehmen.

function varyArg () {
    return arguments[0] + arguments[1];
}

Wenn ein anderer Entwickler Ihren Code durchsucht, ist es sehr einfach anzunehmen, dass diese Funktion keine Parameter akzeptiert. Insbesondere, wenn dieser Entwickler nicht mit dem Argument- Schlüsselwort vertraut ist. Aus diesem Grund ist es eine gute Idee, eine Stilrichtlinie zu befolgen und konsequent zu sein. Ich werde Google für alle Beispiele verwenden.

Lassen Sie uns explizit angeben, dass dieselbe Funktion variable Parameter hat:

function varyArg (var_args) {
    return arguments[0] + arguments[1];
}

Objektparameter VS var_args

Es kann vorkommen, dass ein Objekt benötigt wird, da es die einzige genehmigte und als Best-Practice-Methode angesehene Methode einer Datenkarte ist. Assoziative Arrays werden verpönt und entmutigt.

SIDENOTE: Das Argument-Schlüsselwort gibt tatsächlich ein Objekt zurück, wobei Zahlen als Schlüssel verwendet werden. Die prototypische Vererbung ist auch die Objektfamilie. Informationen zur ordnungsgemäßen Verwendung des Arrays in JS finden Sie am Ende der Antwort

In diesem Fall können wir dies auch explizit angeben. Hinweis: Diese Namenskonvention wird nicht von Google bereitgestellt, sondern ist ein Beispiel für die explizite Deklaration des Parametertyps. Dies ist wichtig, wenn Sie ein strengeres typisiertes Muster in Ihrem Code erstellen möchten.

function varyArg (args_obj) {
    return args_obj.name+" "+args_obj.weight;
}
varyArg({name: "Brian", weight: 150});

Welches soll ich wählen?

Dies hängt von den Anforderungen Ihrer Funktion und Ihres Programms ab. Wenn Sie beispielsweise einfach eine Wertebasis für einen iterativen Prozess über alle übergebenen Argumente zurückgeben möchten, bleiben Sie mit Sicherheit beim Schlüsselwort argument . Wenn Sie eine Definition Ihrer Argumente und eine Zuordnung der Daten benötigen, ist die Objektmethode der richtige Weg. Schauen wir uns zwei Beispiele an und dann sind wir fertig!

Verwendung von Argumenten

function sumOfAll (var_args) {
    return arguments.reduce(function(a, b) {
        return a + b;
    }, 0);
}
sumOfAll(1,2,3); // returns 6

Objektnutzung

function myObjArgs(args_obj) {
    // MAKE SURE ARGUMENT IS AN OBJECT OR ELSE RETURN
    if (typeof args_obj !== "object") {
        return "Arguments passed must be in object form!";
    }

    return "Hello "+args_obj.name+" I see you're "+args_obj.age+" years old.";
}
myObjArgs({name: "Brian", age: 31}); // returns 'Hello Brian I see you're 31 years old

Zugriff auf ein Array anstelle eines Objekts ("... args" Der Rest-Parameter)

Wie oben in der Antwort erwähnt, gibt das Argument- Schlüsselwort tatsächlich ein Objekt zurück. Aus diesem Grund muss jede Methode aufgerufen werden, die Sie für ein Array verwenden möchten. Ein Beispiel dafür:

Array.prototype.map.call(arguments, function (val, idx, arr) {});

Um dies zu vermeiden, verwenden Sie den Rest-Parameter:

function varyArgArr (...var_args) {
    return var_args.sort();
}
varyArgArr(5,1,3); // returns 1, 3, 5
Brian Ellis
quelle
5

Verwenden Sie das argumentsObjekt innerhalb der Funktion, um Zugriff auf alle übergebenen Argumente zu erhalten.

Nickytonline
quelle
3

Beachten Sie, dass das Übergeben eines Objekts mit benannten Eigenschaften, wie von Ken vorgeschlagen, die Kosten für das Zuweisen und Freigeben des temporären Objekts für jeden Aufruf erhöht. Das Übergeben normaler Argumente als Wert oder Referenz ist im Allgemeinen am effizientesten. Für viele Anwendungen ist die Leistung zwar nicht kritisch, für einige jedoch.

phbcanada
quelle