Numero variabile JavaScript di argomenti da funzionare


531

Esiste un modo per consentire var "illimitati" per una funzione in JavaScript?

Esempio:

load(var1, var2, var3, var4, var5, etc...)
load(var1)


relativo / possibile duplicato di stackoverflow.com/questions/4633125/…
Luca

1
@ Luca no, non lo è. Questa domanda chiede come chiamare una funzione con un numero arbitrario di argomenti con gli argomenti in un array. Questo chiede come gestire una simile chiamata.
Scruffy,

1
Per una ricerca più semplice, tale funzione è chiamata "funzione variadica".
gschenk,

Risposte:


814

Certo, basta usare l' argumentsoggetto.

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

1
Tnx. È ottimo per analizzare le stringhe dal codice nativo Android a JavaScript in una visualizzazione Web.
Johan Hoeksma,

4
Questa soluzione ha funzionato meglio per me. Grazie. Ulteriori informazioni sulla parola chiave argomenti QUI .
Utente2

26
argumentsè un oggetto speciale "simile a matrice", il che significa che ha una lunghezza, ma non ha altre funzioni di matrice. Vedere developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/… per ulteriori informazioni e questa risposta: stackoverflow.com/a/13145228/1766230
Luca,

4
È interessante notare che i metodi Array in Javascript sono stati definiti in modo tale da funzionare su qualsiasi oggetto che abbia una lengthproprietà. Questo include l' argumentsoggetto. Sapendo questo, e che il metodo concatrestituisce una copia del 'allineamento' si chiama in poi, si può facilmente convertire l' argumentsoggetto in una matrice reale come questo: var args = [].concat.call(arguments). Alcune persone preferiscono usare Array.prototype.concat.callinvece, ma mi piace [], sono brevi e dolci!
Stijn de Witt,

2
@YasirJan use[...arguments].join()
Willian D. Andrade,

179

Nella (maggior parte) dei browser recenti, puoi accettare un numero variabile di argomenti con questa sintassi:

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

Ecco un piccolo esempio:

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

Documentazione e altri esempi qui: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/rest_parameters


27
Cordiali saluti si chiama "la sintassi del parametro rest": developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
tanguy_k

4
+1 Questa è una soluzione elegante e pulita. Particolarmente adatto per passare attraverso un lungo elenco di parametri in un'altra chiamata di funzione e con la possibilità che tali parametri variabili siano in posizione arbitraria.
haxpor,

3
Tieni presente che, secondo developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/… , non è supportato su IE.
Roee Gavirel,

2
Ecco una tabella che mostra il supporto del browser - caniuse.com/#feat=rest-parameters
Brian Burns

1
Che bella risposta!
Ashish,

113

Un'altra opzione è passare i tuoi argomenti in un oggetto di contesto.

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

e usalo in questo modo

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

Questo ha il vantaggio di poter aggiungere tutti gli argomenti nominati che desideri e la funzione può usarli (o meno) come ritiene opportuno.


4
Ciò sarebbe meglio poiché rimuove l'accoppiamento all'ordine degli argomenti. Le interfacce liberamente accoppiate sono una buona pratica standard ...
Jonas Schubert Erlandsson,

9
Certo, in alcuni casi è meglio. Ma supponiamo che i singoli argomenti non si relazionino realmente l'uno con l'altro o che tutti abbiano lo stesso significato (come gli elementi dell'array). Quindi il modo di OP è il migliore.
rvighne,

1
Questo è anche bello perché se vuoi, puoi costruire l' contextargomento con il codice e passarlo prima che venga usato.
Nate CK,

46

Concordo con la risposta di Ken come la più dinamica e mi piace fare un passo avanti. Se è una funzione che chiami più volte con argomenti diversi, utilizzo il design di Ken ma aggiungo i valori predefiniti:

function load(context) {

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

    var context = extend(defaults, context);

    // do stuff
}

In questo modo, se si hanno molti parametri ma non è necessario impostarli con ciascuna chiamata alla funzione, è possibile specificare semplicemente i valori predefiniti. Per il metodo di estensione, puoi utilizzare il metodo di estensione di jQuery ( $.extend()), crearne uno tuo o utilizzare quanto segue:

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

Ciò unirà l'oggetto di contesto con i valori predefiniti e inserirà i valori non definiti nell'oggetto con i valori predefiniti.


3
+1. Bel trucco. Salva molta piastra della caldaia per avere tutti i parametri definiti, predefiniti o meno.
Neil,

1
Il _.defaults() metodo di Underscore è un'ottima alternativa per unire argomenti specifici e predefiniti.
mbeasley,

18

Sì, proprio così:

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

load(1,2);

18

È preferibile utilizzare la sintassi dei parametri di riposo, come ha sottolineato Ramast.

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

Voglio solo aggiungere qualche bella proprietà dell'argomento ... args

  1. È un array e non un oggetto come gli argomenti. Ciò consente di applicare funzioni come la mappa o l'ordinamento direttamente.
  2. Non include tutti i parametri ma solo quello passato da esso in poi. Ad esempio, la funzione (a, b, ... args) in questo caso args contiene l'argomento 3 a argument.length

15

Come già accennato, è possibile utilizzare l' argumentsoggetto per recuperare un numero variabile di parametri di funzione.

Se si desidera chiamare un'altra funzione con gli stessi argomenti, utilizzare apply. Puoi anche aggiungere o rimuovere argomenti convertendoli argumentsin un array. Ad esempio, questa funzione inserisce del testo prima di accedere alla console:

log() {
    let args = Array.prototype.slice.call(arguments);
    args = ['MyObjectName', this.id_].concat(args);
    console.log.apply(console, args);
}

bella soluzione per convertire argomenti in array. Mi è stato utile oggi.
Dmytro Medvid,

8

Anche se generalmente sono d'accordo sul fatto che l'approccio degli argomenti nominati sia utile e flessibile (a meno che non ti interessi all'ordine, nel qual caso gli argomenti sono i più facili), ho delle preoccupazioni sul costo dell'approccio mbeasley (usando i valori predefiniti e le estensioni). Questa è una quantità estrema di costi da prendere per estrarre i valori predefiniti. Innanzitutto, i valori predefiniti sono definiti all'interno della funzione, quindi vengono ripopolati ad ogni chiamata. In secondo luogo, puoi facilmente leggere i valori nominati e impostare i valori predefiniti contemporaneamente utilizzando ||. Non è necessario creare e unire ancora un altro nuovo oggetto per ottenere queste informazioni.

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

   // do stuff
}

Si tratta approssimativamente della stessa quantità di codice (forse leggermente più), ma dovrebbe essere una frazione del costo di runtime.


Concordato, sebbene il danno dipenda dal tipo di valore o dal default stesso. Altrimenti, (parameter1=context.parameter1)===undefined && (parameter1=defaultValue1)o per meno volume di codice, una funzione di supporto piccola come: function def(providedValue, default) {return providedValue !== undefined ? providedValue : defaultValue;} var parameter1 = def(context.parameter1, defaultValue1)fornisce schemi alternativi. Tuttavia, il mio punto è ancora valido: la creazione di oggetti extra per ogni invocazione di funzioni e l'esecuzione di costosi loop per impostare un paio di valori predefiniti è una quantità folle di sovraccarico.
mcurland,

7

Mentre @roufamatic ha mostrato l'uso della parola chiave argomenti e @Ken ha mostrato un ottimo esempio di un oggetto per l'uso, non mi sento né veramente indirizzato a ciò che sta succedendo in questo caso e posso confondere i lettori futuri o instillare una cattiva pratica come non affermare esplicitamente una funzione / method è destinato a prendere una quantità variabile di argomenti / parametri.

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

Quando un altro sviluppatore sta esaminando il tuo codice, è molto facile supporre che questa funzione non abbia parametri. Soprattutto se quello sviluppatore non è a conoscenza della parola chiave argomenti . Per questo motivo è una buona idea seguire una linea guida di stile ed essere coerenti. Userò Google per tutti gli esempi.

Dichiariamo esplicitamente che la stessa funzione ha parametri variabili:

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

Parametro oggetto VS var_args

Ci possono essere momenti in cui un oggetto è necessario in quanto è l'unico metodo approvato e considerato best practice di una mappa di dati. Gli array associativi sono disapprovati e scoraggiati.

NOTA A MARGINE: la parola chiave argomenti restituisce effettivamente un oggetto usando i numeri come chiave. L'eredità prototipale è anche la famiglia di oggetti. Vedere la fine della risposta per un corretto utilizzo dell'array in JS

In questo caso possiamo affermare esplicitamente anche questo. Nota: questa convenzione di denominazione non è fornita da Google ma è un esempio di dichiarazione esplicita del tipo di un parametro. Questo è importante se stai cercando di creare un modello tipizzato più rigoroso nel tuo codice.

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

Quale scegliere?

Questo dipende dalle esigenze della tua funzione e del programma. Se ad esempio stai semplicemente cercando di restituire una base di valori su un processo iterativo su tutti gli argomenti passati, sicuramente segui la parola chiave argomenti . Se hai bisogno di definizione dei tuoi argomenti e mappatura dei dati, allora il metodo dell'oggetto è la strada da percorrere. Diamo un'occhiata a due esempi e poi abbiamo finito!

Utilizzo degli argomenti

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

Utilizzo dell'oggetto

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

Accesso a un array anziché a un oggetto ("... args" Il parametro rest)

Come accennato all'inizio della risposta, la parola chiave argomenti restituisce effettivamente un oggetto. Per questo motivo, sarà necessario chiamare qualsiasi metodo che si desidera utilizzare per un array. Un esempio di questo:

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

Per evitare ciò, utilizzare il parametro rest:

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

5

Utilizzare l' argumentsoggetto all'interno della funzione per avere accesso a tutti gli argomenti passati.


3

Tenere presente che il passaggio di un oggetto con proprietà denominate come suggerito da Ken aggiunge il costo di allocazione e rilascio dell'oggetto temporaneo per ogni chiamata. Passare argomenti normali per valore o riferimento sarà generalmente il più efficiente. Per molte applicazioni, sebbene le prestazioni non siano critiche, ma per alcune può esserlo.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.