¿Hay alguna manera de permitir variables "ilimitadas" para una función en JavaScript?
Ejemplo:
load(var1, var2, var3, var4, var5, etc...)
load(var1)
¿Hay alguna manera de permitir variables "ilimitadas" para una función en JavaScript?
Ejemplo:
load(var1, var2, var3, var4, var5, etc...)
load(var1)
Respuestas:
Claro, solo usa el arguments
objeto.
function foo() {
for (var i = 0; i < arguments.length; i++) {
console.log(arguments[i]);
}
}
arguments
es un objeto especial "tipo matriz", lo que significa que tiene una longitud, pero ninguna otra función de matriz. Consulte developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/… para obtener más información, y esta respuesta: stackoverflow.com/a/13145228/1766230
length
propiedad. Esto incluye el arguments
objeto. Sabiendo esto, y que el método concat
devuelve una copia de la 'matriz' se llama en adelante, podemos fácilmente convertir el arguments
objeto a una matriz real como esto: var args = [].concat.call(arguments)
. Algunas personas prefieren usar Array.prototype.concat.call
en su lugar, pero me gusta []
, ¡son cortas y dulces!
[...arguments].join()
En (la mayoría) de los navegadores recientes, puede aceptar un número variable de argumentos con esta sintaxis:
function my_log(...args) {
// args is an Array
console.log(args);
// You can pass this array as parameters to another function
console.log(...args);
}
Aquí hay un pequeño ejemplo:
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
Documentación y más ejemplos aquí: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/rest_parameters
Otra opción es pasar sus argumentos en un objeto de contexto.
function load(context)
{
// do whatever with context.name, context.address, etc
}
y úsalo así
load({name:'Ken',address:'secret',unused:true})
Esto tiene la ventaja de que puede agregar tantos argumentos con nombre como desee, y la función puede usarlos (o no) como mejor le parezca.
context
argumento con código y pasarlo antes de que se use.
Estoy de acuerdo con la respuesta de Ken como la más dinámica y me gusta ir un paso más allá. Si es una función que llama varias veces con diferentes argumentos, uso el diseño de Ken pero luego agrego valores predeterminados:
function load(context) {
var defaults = {
parameter1: defaultValue1,
parameter2: defaultValue2,
...
};
var context = extend(defaults, context);
// do stuff
}
De esta manera, si tiene muchos parámetros pero no necesariamente necesita establecerlos con cada llamada a la función, simplemente puede especificar los valores no predeterminados. Para el método extendido, puede usar el método extendido de jQuery ( $.extend()
), crear el suyo propio o usar lo siguiente:
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];
}
Esto fusionará el objeto de contexto con los valores predeterminados y completará cualquier valor indefinido en su objeto con los valores predeterminados.
_.defaults()
método de subrayado es una muy buena alternativa para fusionar argumentos especificados y predeterminados.
Es preferible utilizar la sintaxis del parámetro rest como señaló Ramast.
function (a, b, ...args) {}
Solo quiero agregar alguna buena propiedad del argumento ... args
- Es una matriz, y no un objeto como los argumentos. Esto le permite aplicar funciones como mapear u ordenar directamente.
- No incluye todos los parámetros, sino solo el que se transmitió. Por ejemplo, la función (a, b, ... args) en este caso args contiene el argumento 3 a argumentos.length
Como ya se mencionó, puede usar el arguments
objeto para recuperar un número variable de parámetros de función.
Si desea llamar a otra función con los mismos argumentos, use apply
. Incluso puede agregar o eliminar argumentos mediante la conversión arguments
a una matriz. Por ejemplo, esta función inserta texto antes de iniciar sesión en la consola:
log() {
let args = Array.prototype.slice.call(arguments);
args = ['MyObjectName', this.id_].concat(args);
console.log.apply(console, args);
}
Aunque generalmente estoy de acuerdo en que el enfoque de los argumentos nombrados es útil y flexible (a menos que le importe el orden, en cuyo caso los argumentos son más fáciles), me preocupa el costo del enfoque de mbeasley (uso de valores predeterminados y ampliaciones). Esta es una cantidad extrema de costo a tomar para extraer valores predeterminados. Primero, los valores predeterminados se definen dentro de la función, por lo que se vuelven a llenar en cada llamada. En segundo lugar, puede leer fácilmente los valores nombrados y establecer los valores predeterminados al mismo tiempo usando ||. No es necesario crear y fusionar otro objeto nuevo para obtener esta información.
function load(context) {
var parameter1 = context.parameter1 || defaultValue1,
parameter2 = context.parameter2 || defaultValue2;
// do stuff
}
Esto es aproximadamente la misma cantidad de código (quizás un poco más), pero debería ser una fracción del costo de tiempo de ejecución.
(parameter1=context.parameter1)===undefined && (parameter1=defaultValue1)
o por menos volumen de código, una pequeña función auxiliar como: function def(providedValue, default) {return providedValue !== undefined ? providedValue : defaultValue;} var parameter1 = def(context.parameter1, defaultValue1)
proporcionar patrones alternativos. Sin embargo, mi punto sigue en pie: crear objetos adicionales para cada invocación de función y ejecutar bucles costosos para establecer un par de valores predeterminados es una gran cantidad de sobrecarga.
Si bien @roufamatic mostró el uso de la palabra clave de argumentos y @Ken mostró un gran ejemplo de un objeto para su uso, no siento que haya abordado realmente lo que está sucediendo en este caso y puede confundir a los futuros lectores o inculcar una mala práctica al no indicar explícitamente una función / método está destinado a tomar una cantidad variable de argumentos / parámetros.
function varyArg () {
return arguments[0] + arguments[1];
}
Cuando otro desarrollador está revisando su código, es muy fácil asumir que esta función no toma parámetros. Especialmente si ese desarrollador no está al tanto de los argumentos palabra clave de . Debido a esto, es una buena idea seguir una pauta de estilo y ser coherente. Usaré Google para todos los ejemplos.
Digamos explícitamente que la misma función tiene parámetros variables:
function varyArg (var_args) {
return arguments[0] + arguments[1];
}
Puede haber ocasiones en que se necesite un objeto, ya que es el único método de mejores prácticas aprobado y considerado de un mapa de datos. Las matrices asociativas están mal vistas y desaconsejadas.
NOTA AL MARGEN: La palabra clave argumentos en realidad devuelve un objeto usando números como clave. La herencia prototípica es también la familia de objetos. Vea el final de la respuesta para el uso apropiado de la matriz en JS
En este caso, también podemos declarar esto explícitamente. Nota: Google no proporciona esta convención de nomenclatura, pero es un ejemplo de declaración explícita del tipo de un parámetro. Esto es importante si está buscando crear un patrón escrito más estricto en su código.
function varyArg (args_obj) {
return args_obj.name+" "+args_obj.weight;
}
varyArg({name: "Brian", weight: 150});
Esto depende de las necesidades de su función y programa. Si, por ejemplo, simplemente está buscando devolver una base de valores en un proceso iterativo en todos los argumentos pasados, entonces seguramente se quedará con la palabra clave argumentos . Si necesita definir sus argumentos y mapear los datos, entonces el método del objeto es el camino a seguir. ¡Veamos dos ejemplos y luego terminamos!
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
Como se menciona arriba de la respuesta, la palabra clave argumentos en realidad devuelve un objeto. Debido a esto, se deberá llamar a cualquier método que desee utilizar para una matriz. Un ejemplo de esto:
Array.prototype.map.call(arguments, function (val, idx, arr) {});
Para evitar esto, use el parámetro rest:
function varyArgArr (...var_args) {
return var_args.sort();
}
varyArgArr(5,1,3); // returns 1, 3, 5
Use el arguments
objeto dentro de la función para tener acceso a todos los argumentos pasados.
Tenga en cuenta que pasar un Objeto con propiedades con nombre como Ken sugirió agrega el costo de asignar y liberar el objeto temporal a cada llamada. Pasar argumentos normales por valor o referencia generalmente será el más eficiente. Para muchas aplicaciones, aunque el rendimiento no es crítico, pero para algunas sí puede serlo.