Ist es möglich, eine variable Anzahl von Argumenten an eine JavaScript-Funktion zu senden?

168

Ist es möglich, eine variable Anzahl von Argumenten von einem Array an eine JavaScript-Funktion zu senden?

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'

Ich habe kürzlich viel Python geschrieben und es ist ein wunderbares Muster, Varargs akzeptieren und senden zu können. z.B

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'

Ist es in JavaScript möglich, ein Array zu senden, das als Argumentarray behandelt wird ?

Feuerkrähe
quelle
4
Beachten Sie, dass es keine gute Idee ist, eine for - inSchleife mit dem argumentsObjekt lengthzu verwenden
Yi Jiang
2
Es war noch nie ein Problem. Können Sie herausfinden, warum dies der Fall ist? Das Argument-Objekt ist fast immer klein genug, um eine vernachlässigbare Leistungsverbesserung für die Verwendung der Version agruments [0..length-1] zu erzielen.
Feuerkrähe
Mögliches Duplikat der JavaScript-Variablen Anzahl der zu funktionierenden Argumente
Anderson Green
1
Ich denke, dass Argumente kein tatsächliches Array sind, sondern ein spezielles Objekt, daher funktioniert die "in" -Syntax je nach JS-Implementierung möglicherweise nicht.
O'Rooney

Antworten:

205

Update : Seit ES6 können Sie beim Aufrufen der Funktion einfach die Spread-Syntax verwenden:

func(...arr);

Da ES6 auch dann, wenn Sie erwarten, Ihre Argumente als Array zu behandeln, können Sie die Spread-Syntax in der Parameterliste verwenden, zum Beispiel:

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

const values = ['a', 'b', 'c']
func(...values)
func(1, 2, 3)

Und Sie können es mit normalen Parametern kombinieren, zum Beispiel, wenn Sie die ersten beiden Argumente separat und den Rest als Array erhalten möchten:

function func(first, second, ...theRest) {
  //...
}

Und vielleicht ist es für Sie nützlich, dass Sie wissen, wie viele Argumente eine Funktion erwartet:

var test = function (one, two, three) {}; 
test.length == 3;

Aber trotzdem können Sie eine beliebige Anzahl von Argumenten übergeben ...

Die Spread-Syntax ist kürzer und "süßer" als applyund wenn Sie den thisWert nicht im Funktionsaufruf festlegen müssen , ist dies der richtige Weg.

Hier ist ein Anwendungsbeispiel , wie es früher gemacht wurde:

var arr = ['a','b','c'];

function func() {
  console.log(this); // 'test'
  console.log(arguments.length); // 3

  for(var i = 0; i < arguments.length; i++) {
    console.log(arguments[i]);
  }

};

func.apply('test', arr);

Heutzutage empfehle ich die Verwendung applynur, wenn Sie eine beliebige Anzahl von Argumenten aus einem Array übergeben und den thisWert festlegen müssen . applyTakes ist der thisWert als erstes Argument, das beim Aufrufen der Funktion verwendet wird. Wenn wir ihn nullin nicht striktem Code verwenden, thisverweist das Schlüsselwort funcim strikten Modus auf das globale Objekt (Fenster) im Inneren , wenn explizit 'use strict' verwendet wird 'oder in ES-Modulen nullverwendet werden.

Beachten Sie auch, dass das argumentsObjekt nicht wirklich ein Array ist. Sie können es konvertieren durch:

var argsArray = Array.prototype.slice.call(arguments);

Und in ES6:

const argsArray = [...arguments] // or Array.from(arguments)

argumentsDank der Spread-Syntax wird das Objekt heutzutage jedoch nur noch selten direkt verwendet.

CMS
quelle
1
Danke, bewerben macht den Trick, Anruf funktioniert in diesem Fall nicht. Wurde das versehentlich geschrieben?
Feuer Crow
Wie machen Sie das, wenn die Funktion tatsächlich Mitglied einer Klasse ist? Ist das richtig? theObject.member.apply (theObject, Argumente);
Baxissimo
4
Array.prototype.slice.call(arguments);verhindert Browser-JS-Optimierungen wie V8. Details hier
Dheeraj Bhaskar
2
1. Anscheinend argumentsist geplant, zugunsten des Spread-Betreibers veraltet zu sein . Ich habe keine Quelle dafür, aber ich habe es irgendwo gehört. 2. MDN gibt an, dass die Verwendung slicedes argumentsObjekts Optimierungen in Engines wie V8 verhindert. Sie schlagen vor, den "verachteten Array-Konstruktor" zu verwenden Array.from(arguments), oder [...arguments]. Möchten Sie Ihre Antwort für ES2015 aktualisieren?
Braden Best
NB: Ich habe meine eigene Antwort geschrieben .
Braden Best
75

Sie können tatsächlich so viele Werte an eine Javascript-Funktion übergeben, wie Sie möchten. Die explizit benannten Parameter erhalten die ersten Werte, aber ALLE Parameter werden im Argumentarray gespeichert.

Um das Argumentarray in "entpackter" Form zu übergeben, können Sie apply wie folgt verwenden (siehe 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);
danben
quelle
23

Die Splat- und Spread- Operatoren sind Teil von ES6, der geplanten nächsten Version von Javascript. Bisher unterstützt sie nur Firefox. Dieser Code funktioniert in 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');

Beachten Sie die unangenehme Syntax für die Verbreitung. Die übliche Syntax von sprintf('The %s %s fox jumps over the %s dog.', ...arr);wird noch nicht unterstützt . Eine ES6-Kompatibilitätstabelle finden Sie hier .

Beachten Sie auch die Verwendung eines for...ofweiteren ES6-Zusatzes. Die Verwendung for...infür Arrays ist eine schlechte Idee .

Tgr
quelle
Die normale Syntax für die Verbreitung wird jetzt in Firefox und Chrome unterstützt
Benutzer
8

Die applyFunktion akzeptiert zwei Argumente. Das Objekt thiswird gebunden und die Argumente mit einem Array dargestellt.

some_func = function (a, b) { return b }
some_func.apply(obj, ["arguments", "are", "here"])
// "are"
August Lilleaas
quelle
8

Ab ES2015 gibt es zwei Methoden.

Das argumentsObjekt

Dieses Objekt ist in Funktionen integriert und verweist entsprechend auf die Argumente einer Funktion. Da es sich technisch gesehen jedoch nicht um ein Array handelt, funktionieren typische Array-Operationen nicht. Die vorgeschlagene Methode besteht darin, mit Array.fromdem Spread-Operator ein Array daraus zu erstellen.

Ich habe andere Antworten gesehen, die die Verwendung erwähnen slice. Tu das nicht. Es verhindert Optimierungen (Quelle: MDN ).

Array.from(arguments)
[...arguments]

Ich würde jedoch argumentieren, dass dies argumentsproblematisch ist, da es verbirgt, was eine Funktion als Eingabe akzeptiert. Eine argumentsFunktion ist normalerweise folgendermaßen geschrieben:

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

Manchmal wird der Funktionsheader wie folgt geschrieben, um die Argumente C-ähnlich zu dokumentieren:

function mean(/* ... */){ ... }

Das ist aber selten.

Nehmen Sie zum Beispiel C, warum dies problematisch ist. C ist abwärtskompatibel mit einem alten Prä-ANSI-Dialekt der Sprache K & R C. Mit K & R C können Funktionsprototypen eine leere Argumentliste haben.

int myFunction();
/* This function accepts unspecified parameters */

ANSI C bietet die Möglichkeit, varargs( ...) und voideine leere Argumentliste anzugeben.

int myFunction(void);
/* This function accepts no parameters */

Viele Leute deklarieren versehentlich Funktionen mit einer unspecifiedArgumentliste ( int myfunction();), wenn sie erwarten, dass die Funktion keine Argumente akzeptiert. Dies ist technisch gesehen ein Fehler , weil die Funktion wird Argumente akzeptieren. Beliebig viele von ihnen.

Eine ordnungsgemäße varargsFunktion in C hat folgende Form:

int myFunction(int nargs, ...);

Und JavaScript hat tatsächlich etwas Ähnliches.

Spread Operator / Rest-Parameter

Ich habe Ihnen den Spread-Operator bereits gezeigt.

...name

Es ist ziemlich vielseitig und kann auch in der Argumentliste einer Funktion ("Restparameter") verwendet werden, um Varargs auf gut dokumentierte Weise anzugeben:

function mean(...args){
    return args.reduce((a,b)=>a+b) / args.length;
}

Oder als Lambda-Ausdruck:

((...args)=>args.reduce((a,b)=>a+b) / args.length)(1,2,3,4,5); // 3

Ich bevorzuge den Spread-Operator. Es ist sauber und selbstdokumentierend.

Braden Best
quelle
2
Vielen Dank für die aktualisierte Antwort. Dieser Beitrag stammt aus der Zeit vor der ES 2015, daher bin ich froh, dass Sie neuere Optionen ausgefüllt haben
Fire Crow,
5

Es heißt der splatOperator. Sie können dies in JavaScript tun, indem Sie 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); 
Chandra Patni
quelle
4

Mit ES6 können Sie Ruheparameter für verwenden varagrs. Dies nimmt die Argumentliste und konvertiert sie in ein Array.

function logArgs(...args) {
    console.log(args.length)
    for(let arg of args) {
        console.log(arg)
    }
}
theres.yer.problem
quelle
2

Dies ist ein Beispielprogramm zum Berechnen der Summe von Ganzzahlen für variable Argumente und Arrays für Ganzzahlen. Hoffe das hilft.

var CalculateSum = function(){
    calculateSumService.apply( null, arguments );
}

var calculateSumService = function(){
    var sum = 0;

    if( arguments.length === 1){
        var args = arguments[0];

        for(var i = 0;i<args.length; i++){
           sum += args[i]; 
        }
    }else{
        for(var i = 0;i<arguments.length; i++){
           sum += arguments[i]; 
        }        
    }

     alert(sum);

}


//Sample method call

// CalculateSum(10,20,30);         

// CalculateSum([10,20,30,40,50]);

// CalculateSum(10,20);
Streifen
quelle
1
Einige Hinweise: 1. vardeklariert eine function scopeVariable. Die Wörter new letund constkeywords (ES 2015) deklarieren block scopeVariablen. Vor ES 2015 sollten die Variablen jedoch aus praktischen Gründen noch an die Spitze der Funktion gehoben worden sein. 2. Ihre Funktion bricht ab, wenn 1 ganzzahliger Wert angegeben wird, weil Sie ein Array fälschlicherweise als Argument akzeptiert haben (in der Frage wird nach varargs gefragt; Arrays werden nicht als Argumente akzeptiert) : CalculateSum(6) -> 0. (Fortsetzung im nächsten Beitrag)
Braden Best
1
3. Verwenden Sie keine Debug-Funktionen wie alert. Eigentlich nur nicht verwenden alert/prompt/confirm, Punkt. Verwenden Sie console.logstattdessen beim Debuggen. 4. Die Funktion sollte returnein Wert sein, nicht ein Wert alert. 5. Vermeiden Sie PascalCasees, es sei denn, es bezieht sich auf einen "Datentyp". Dh eine Klasse. Verwenden Sie camelCaseoder under_scorestattdessen. 4. Mir gefällt nicht, wie Sie Ihre Funktionen deklarieren. var f = function(){ ... }impliziert, dass Sie möchten, dass es sich irgendwann ändert , was wahrscheinlich nicht Ihre Absicht ist. Verwenden Sie function name(){ ... }stattdessen die herkömmliche Syntax.
Braden Best
Um all diese Kritikpunkte zu demonstrieren, finden Sie hier eine verbesserte Version der Funktion in Ihrer Antwort.
Braden Best
2
(function(window) {
  var proxied = window.alert;
  window.alert = function() {
    return proxied.apply(window, arguments);
  };
}(this));

alert(13, 37);
yckart
quelle
1

Für diejenigen, die hier von der Übergabe einer variablen Anzahl von Argumenten von einer Funktion an eine andere umgeleitet wurden (was nicht sollte) als Duplikat dieser Frage markiert werden ):

Wenn Sie versuchen, eine variable Anzahl von Argumenten von einer Funktion an eine andere zu übergeben, können Sie seit JavaScript 1.8.5 einfach apply()die zweite Funktion aufrufen und den argumentsParameter übergeben:

var caller = function()
{
    callee.apply( null, arguments );
}

var callee = function()
{
    alert( arguments.length );
}

caller( "Hello", "World!", 88 ); // Shows "3".

Hinweis: Das erste Argument ist der thiszu verwendende Parameter. Vorbeigehennull wird die Funktion aus dem globalen Kontext aufgerufen, dh als globale Funktion anstelle der Methode eines Objekts.

Gemäß diesem Dokument wurde in der ECMAScript 5-Spezifikation die apply()Methode neu definiert , um ein "generisches Array-ähnliches Objekt" anstelle eines strengen Arrays zu verwenden. So können Sie die argumentsListe direkt an die zweite Funktion übergeben.

Getestet in Chrome 28.0, Safari 6.0.5 und IE 10. Probieren Sie es mit dieser JSFiddle aus .

andrewtc
quelle
0

Ja, Sie können die Variable nein übergeben. von Argumenten zu einer Funktion. Sie können verwendenapply , um dies zu erreichen.

Z.B:

var arr = ["Hi","How","are","you"];

function applyTest(){
    var arg = arguments.length;
    console.log(arg);
}

applyTest.apply(null,arr);
Abhijit
quelle
0

Möchten Sie, dass Ihre Funktion auf ein Array-Argument oder variable Argumente reagiert? Wenn letzteres der Fall ist, versuchen Sie:

var func = function(...rest) {
  alert(rest.length);

  // In JS, don't use for..in with arrays
  // use for..of that consumes array's pre-defined iterator
  // or a more functional approach
  rest.forEach((v) => console.log(v));
};

Aber wenn Sie ein Array-Argument behandeln möchten

var fn = function(arr) {
  alert(arr.length);

  for(var i of arr) {
    console.log(i);
  }
};
Dev Yego
quelle