¿Es posible obtener todos los argumentos de una función como un solo objeto dentro de esa función?

Respuestas:

346

Uso arguments. Puedes acceder a él como una matriz. Úselo arguments.lengthpara la cantidad de argumentos.

Thomas Eding
fuente
46
Esto solo funciona para el JavaScript tradicional function, no para las =>funciones de flecha gruesa ES2015 + . Para aquellos, podrás quiero usar ...argsen la definición de función, así: (...args) => console.log(args).
Sawtaytoes
141

Los argumentos son un objeto tipo matriz (no una matriz real). Función de ejemplo ...

function testArguments () // <-- notice no arguments specified
{
    console.log(arguments); // outputs the arguments to the console
    var htmlOutput = "";
    for (var i=0; i < arguments.length; i++) {
        htmlOutput += '<li>' + arguments[i] + '</li>';
    }
    document.write('<ul>' + htmlOutput + '</ul>');
}

Pruébalo...

testArguments("This", "is", "a", "test");  // outputs ["This","is","a","test"]
testArguments(1,2,3,4,5,6,7,8,9);          // outputs [1,2,3,4,5,6,7,8,9]

Los detalles completos: https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Functions_and_function_scope/arguments

Luke
fuente
3
¿Por qué no publicar el resultado aquí también? :)
Jonathan Azulay
2
Esto es mucho mejor que la respuesta aceptada porque contiene un fragmento de código de trabajo y muestra la salida. La respuesta aceptada es demasiado escasa.
Mac
Buena respuesta ... sería una gran respuesta al expandir "no una matriz real"
terpinmd
Agregué un enlace a una descripción simple: un "Objeto similar a una matriz" es solo un "Objeto que tiene una propiedad de longitud de un entero no negativo y, por lo general, algunas propiedades indexadas". Desde el enlace de Mozilla: "Es similar a una matriz, pero no tiene ninguna propiedad de matriz excepto la longitud".
Lucas
31

ES6 permite una construcción donde se especifica un argumento de función con una notación "..." como

function testArgs (...args) {
 // Where you can test picking the first element
 console.log(args[0]); 
}
Gunnar Forsgren - Mobimation
fuente
3
Esta parece ser la única forma cuando se utiliza la función de flecha. a = () => {console.log(arguments);}; a('foo');da -- Uncaught ReferenceError: arguments is not defined Sin embargo a = (...args) => {console.log(args);}; a('foo');da["foo"]
David Baucum
1
@DavidBaucum eso es correcto. Debido a que la función de flecha no crea un nuevo ámbito, y los "argumentos" se recopilan del ámbito. Pero el peor de los casos no es un ReferenceError. Es que los "argumentos" se recopilan desde un ámbito externo. Entonces no obtienes ninguna excepción, y tal vez errores extraños en tu aplicación.
pgsandstrom
1
Esto también se llama "parámetros de descanso", vea developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/… .
Dennis
21

El argumentsobjeto es donde se almacenan los argumentos de las funciones.

El objeto de argumentos actúa y parece una matriz, básicamente lo es, simplemente no tiene los métodos que las matrices tienen, por ejemplo:

Array.forEach(callback[, thisArg]);

Array.map(callback[, thisArg])

Array.filter(callback[, thisArg]);

Array.slice(begin[, end])

Array.indexOf(searchElement[, fromIndex])

Creo que la mejor manera de convertir un argumentsobjeto en una matriz real es así:

argumentsArray = [].slice.apply(arguments);

Eso lo convertirá en una matriz;

reutilizable:

function ArgumentsToArray(args) {
    return [].slice.apply(args);
}

(function() {
   args = ArgumentsToArray(arguments);

   args.forEach(function(value) {
      console.log('value ===', value);
   });

})('name', 1, {}, 'two', 3)

resultado:

> value === name
> value === 1
> value === Object {}
> value === two
>value === 3

iConnor
fuente
1
[].slice.apply(arguments);no puede ser la mejor manera porque causa una asignación de matriz vacía innecesaria.
Thomas Eding
10

También puede convertirlo en una matriz si lo prefiere. Si hay genéricos de matriz disponibles:

var args = Array.slice(arguments)

De otra manera:

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

de Mozilla MDN :

No debe dividir los argumentos porque evita las optimizaciones en los motores de JavaScript (V8, por ejemplo).

Iman Mohamadi
fuente
2
Gracias por la actualización. Use JSON.stringify y JSON.parse como alternativa: function foo() { foo.bar = JSON.stringify(arguments); foo.baz = JSON.parse(foo.bar); } si se necesita preservación en lugar de stringificación, use el algoritmo de clonación estructurado interno . Si se pasan los nodos DOM, use XMLSerializer como en una pregunta no relacionada . with (new XMLSerializer()) {serializeToString(document.documentElement) }
Paul Sweatte
7

Como muchos otros señalaron, argumentscontiene todos los argumentos pasados ​​a una función.

Si desea llamar a otra función con los mismos argumentos, use apply

Ejemplo:

var is_debug = true;
var debug = function() {
  if (is_debug) {
    console.log.apply(console, arguments);
  }
}

debug("message", "another argument")
Lasse Skindstad Ebert
fuente
4

Respuesta similar a Gunnar, con un ejemplo más completo: incluso puedes devolver todo de forma transparente:

function dumpArguments(...args) {
  for (var i = 0; i < args.length; i++)
    console.log(args[i]);
  return args;
}

dumpArguments("foo", "bar", true, 42, ["yes", "no"], { 'banana': true });

Salida:

foo
bar
true
42
["yes","no"]
{"banana":true}

https://codepen.io/fnocke/pen/mmoxOr?editors=0010

Frank Nocke
fuente
3

Sí, si no tiene idea de cuántos argumentos son posibles en el momento de la declaración de la función, puede declarar la función sin parámetros y puede acceder a todas las variables mediante una matriz de argumentos que se pasan en el momento de la llamada a la función.

Rubi Saini
fuente
2

En ES6 puedes hacer algo como esto:

function foo(...args) 
{
   let [a,b,...c] = args;

   console.log(a,b,c);
}


foo(1, null,"x",true, undefined);

Kamil Kiełczewski
fuente
1
Incluso puede hacer `` `function foo (a, b, ... c) {console.log (a, b, c); } `` `
TitouanT
-11

En ES6, use Array.from:

function foo()
  {
  foo.bar = Array.from(arguments);
  foo.baz = foo.bar.join();
  }

foo(1,2,3,4,5,6,7);
foo.bar // Array [1, 2, 3, 4, 5, 6, 7]
foo.baz // "1,2,3,4,5,6,7"

Para el código que no es ES6, use JSON.stringify y JSON.parse:

function foo()
  {
  foo.bar = JSON.stringify(arguments); 
  foo.baz = JSON.parse(foo.bar); 
  }

/* Atomic Data */
foo(1,2,3,4,5,6,7);
foo.bar // "{"0":1,"1":2,"2":3,"3":4,"4":5,"5":6,"6":7}"
foo.baz // [object Object]

/* Structured Data */
foo({1:2},[3,4],/5,6/,Date())
foo.bar //"{"0":{"1":2},"1":[3,4],"2":{},"3":"Tue Dec 17 2013 16:25:44 GMT-0800 (Pacific Standard Time)"}"
foo.baz // [object Object]

Si se necesita preservación en lugar de stringificación, use el algoritmo de clonación estructurado interno .

Si se pasan los nodos DOM, use XMLSerializer como en una pregunta no relacionada .

with (new XMLSerializer()) {serializeToString(document.documentElement) }

Si se ejecuta como bookmarklet, es posible que deba ajustar cada argumento de datos estructurados en un constructor de errores para JSON.stringifyque funcione correctamente.

Referencias

Paul Sweatte
fuente
3
Primero: esto clonará los objetos que se pasen. Segundo: no todo se puede encadenar a JSON. A saber: funciones, objetos DOM, dichas fechas se convierten en cadenas como cadenas ...
John Dvorak
@ JanDvorak ¿Puedes editar mi respuesta con una función que maneja objetos DOM, funciones y fechas?
Paul Sweatte
1
+1, al tratar de pasar los argumentos para el informe de errores como una cadena, el objeto termina como una cadena '[argumentos del objeto]' y registrando eso en la consola no muestra los valores. Si bien no parece responder el OP, sí responde mi pregunta, ¡gracias!
John