Cómo obtener una porción de "argumentos"

80

Todo lo que sabes arguments es un objeto especial que contiene todos los argumentos pasados ​​a la función.

Y siempre que no sea una matriz, no puede usar algo como arguments.slice(1) .

Entonces la pregunta: cómo cortar todo menos el primer elemento de arguments ?

UPD :

parece que no hay forma sin convertirlo en una matriz con

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

Si alguien publica otra solución, sería genial, si no, verificaré la primera con la línea anterior como respuesta.

zerkms
fuente
+ zerkms, de hecho, hay una manera mejor que tomarlo argumentsy convertirlo en una matriz, etc. Por favor, vea mi respuesta a continuación.
Umur Karagöz

Respuestas:

20

En realidad, no es necesario entrometerse con las funciones de matriz.

El uso de la sintaxis del parámetro rest ...rest es más limpio y conveniente.

Ejemplo

function argumentTest(first, ...rest) {
  console.log("First arg:" + first);

  // loop through the rest of the parameters
  for (let arg of rest) {
    console.log("- " + arg);
  }
}

// call your function with any number of arguments
argumentTest("first arg", "#2", "more arguments", "this is not an argument but a contradiction");

...Descanso

Umur Karagöz
fuente
Sí, estoy de acuerdo en estos días en que es más conveniente. Te voté a favor, pero no cambiaré retrospectivamente la respuesta marcada de 5 años.
zerkms
2
Ahora, después de otro año, creo que es hora de cambiar a los nuevos estándares ES :-)
zerkms
esa sensación cuando obtienes +15 puntos por una respuesta de un año :-D
zerkms
133

P. ¿Cómo cortar todo menos el primer elemento arguments?

Lo siguiente devolverá una matriz que contiene todos los argumentos excepto el primero:

var slicedArgs = Array.prototype.slice.call(arguments, 1);

No tiene que convertir argumentsprimero a una matriz, hágalo todo en un solo paso.

nnnnnn
fuente
Creo que hay una desventaja con esto. Si solo hay un argumento adicional (además del primero) no se devuelve nada.
Trevor
@Trevor: no, devuelve una matriz con un elemento que es el segundo argumento. (¿Por qué no devolvería nada?)
nnnnnn
4
La recomendación aquí indica que no debe utilizar segmentos en los argumentos porque evita las optimizaciones del motor de JavaScript.
Jonathan Lin
1
se puede encontrar una explicación más detallada aquí
David Chase
4
@ David - El enlace "con detalle" todavía dice no utilizar .slice()en arguments, pero la única razón que se da es que impide la optimización de motores JS de la función. Así que no es que falle, puede que sea ​​más lento. No voy a escribir código para atender la optimización en el motor JS del día, no cuando el motor del mañana podría haber resuelto el problema de optimización y, en cualquier caso, la diferencia probablemente no será perceptible para el usuario en la mayoría de los casos. casos. Es mejor escribir primero un código claro y fácil de mantener, luego volver y optimizar solo si surge un problema de rendimiento medible.
nnnnnn
11

Puede "cortar sin cortar" recorriendo procedimentalmente el objeto de argumentos:

function fun() {
  var args = [];

  for (var i = 1; i < arguments.length; i++) {
    args.push(arguments[i]);
  }

  return args;
}

fun(1, 2, 3, 4, 5); //=> [2, 3, 4, 5]
Paul Rosania
fuente
2
Sí, funciona, pero no tiene sentido en caso de que tengamos un .slice();-)
zerkms
Por supuesto, es más fácil de usar Array.prototype.slice, pero tu pregunta era si había otra forma.
Paul Rosania
sí, gracias por eso ;-) (aunque obviamente sé sobre for
:-P
Jaja, espero no haber sonado trillado. ¡A veces es información útil sobre SO!
Paul Rosania
3
+1 Esta parece ser la única solución correcta para V8. Eche un vistazo a la evaluación comparativa de optimización aquí: jsperf.com/leaky-args
Tom Auger
11

De https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/arguments :

No debe dividir los argumentos porque evita las optimizaciones en los motores JavaScript (V8, por ejemplo). En su lugar, intente construir una nueva matriz iterando a través del objeto de argumentos.

Entonces la respuesta de Paul Rosiana arriba es correcta

bluescrubbie
fuente
4
Tal vez sea así. Pero no veo cómo los motores de optimización no podrían tratar la respuesta aceptada de una sola línea y optimizarla de la forma que deseen. Siempre es una molestia a largo plazo si comenzamos a codificar para los optimizadores (del día); personalmente, prefiero la claridad del código.
akauppi
2
'rebanada' no se altera. Devuelve una copia superficial de los elementos de la matriz original. Los elementos de la matriz original se copian en la matriz devuelta. Entonces no puedo entender cuál es la diferencia entre la copia manual en una nueva matriz y un segmento.
Maxim
A partir de 2018, la advertencia ya no existe. Deberíamos estar a salvo, supongo.
GBF_Gabriel
9

Esta puede ser una forma:

var args = Array.from(arguments).slice(1);
Di Tran
fuente
En estos días no es necesario en absoluto:function foo(...args)
zerkms
@zerkms Estaba a punto de descartar su sugerencia por razones de rendimiento, ¡pero mi prueba muestra los parámetros de descanso como la solución más rápida! gist.github.com/18d590d12aef1e90d2ed262f4fab0c96
Cody Allan Taylor
Mejoran las implementaciones de @CodyAllanTaylor. A menos que tenga una razón realmente importante para no hacerlo, me apegaría a la sintaxis más legible
zerkms
0

Puedes usar el método [].slice.call(arguments, 1)

[] .slice le devolverá el objeto de la función de corte y puede llamarlo como argumentsy 1son los parámetros

Thierryk
fuente
¿Algún cambio que haya revisado en las respuestas publicadas antes de publicar la suya? La respuesta idéntica (e incluso ligeramente mejor, ya que no asigna una matriz desechable) ya está publicada y marcada.
zerkms
0

Puede usar ... rest dentro de la función para separar el primero y el resto de los argumentos:

function foo(arr) {
  const [first, ...rest] = arguments;
  console.log(`first = ${first}`);
  console.log(`rest = ${rest}`);
}
//Then calling the function with 3 arguments:
foo(1,2,3)

ntarlapan
fuente
Sí, el futuro está aquí, finalmente :-D
zerkms