Esiste un modo per consentire var "illimitati" per una funzione in JavaScript?
Esempio:
load(var1, var2, var3, var4, var5, etc...)
load(var1)
Esiste un modo per consentire var "illimitati" per una funzione in JavaScript?
Esempio:
load(var1, var2, var3, var4, var5, etc...)
load(var1)
Risposte:
Certo, basta usare l' arguments
oggetto.
function foo() {
for (var i = 0; i < arguments.length; i++) {
console.log(arguments[i]);
}
}
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
length
proprietà. Questo include l' arguments
oggetto. Sapendo questo, e che il metodo concat
restituisce una copia del 'allineamento' si chiama in poi, si può facilmente convertire l' arguments
oggetto in una matrice reale come questo: var args = [].concat.call(arguments)
. Alcune persone preferiscono usare Array.prototype.concat.call
invece, ma mi piace []
, sono brevi e dolci!
[...arguments].join()
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
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.
context
argomento con il codice e passarlo prima che venga usato.
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.
_.defaults()
metodo di Underscore è un'ottima alternativa per unire argomenti specifici e predefiniti.
È 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
- È un array e non un oggetto come gli argomenti. Ciò consente di applicare funzioni come la mappa o l'ordinamento direttamente.
- 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
Come già accennato, è possibile utilizzare l' arguments
oggetto 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 arguments
in 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);
}
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.
(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.
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];
}
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});
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!
function sumOfAll (var_args) {
return arguments.reduce(function(a, b) {
return a + b;
}, 0);
}
sumOfAll(1,2,3); // returns 6
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
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
Utilizzare l' arguments
oggetto all'interno della funzione per avere accesso a tutti gli argomenti passati.
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.