Muchas funciones integradas de JavaScript admiten una cantidad arbitraria de argumentos.
Por ejemplo:
Math.max(arg1, arg2, ..., argN)
: devuelve el mayor de los argumentos.
Object.assign(dest, src1, ..., srcN)
: copia las propiedades de src1..N
a dest
.
…etcétera.
En este capítulo aprenderemos cómo hacer lo mismo. Y también, cómo pasar matrices a funciones como parámetros.
...
Se puede llamar a una función con cualquier número de argumentos, sin importar cómo esté definida.
Como aquí:
función suma(a, b) { devolver a + b; } alerta( suma(1, 2, 3, 4, 5) );
No habrá error por argumentos “excesivos”. Pero, por supuesto, en el resultado solo se contarán los dos primeros, por lo que el resultado en el código anterior es 3
.
El resto de parámetros se pueden incluir en la definición de la función mediante el uso de tres puntos ...
seguido del nombre del array que los contendrá. Los puntos significan literalmente "reunir los parámetros restantes en una matriz".
Por ejemplo, para reunir todos los argumentos en una matriz args
:
function sumAll(...args) { // args es el nombre de la matriz sea suma = 0; for (sea arg de args) sum += arg; suma de devolución; } alerta( sumaTodo(1) ); // 1 alerta( sumaTodo(1, 2) ); // 3 alerta( sumaTodo(1, 2, 3) ); // 6
Podemos optar por obtener los primeros parámetros como variables y recopilar solo el resto.
Aquí los dos primeros argumentos van en variables y el resto en la matriz titles
:
función mostrarNombre(nombre, apellido, ...títulos) { alerta( nombre + '' + apellido ); // Julio César // el resto va a la matriz de títulos // es decir, títulos = ["Cónsul", "Imperator"] alerta (títulos [0]); // Cónsul alerta (títulos [1]); // Emperador alerta (títulos.longitud); // 2 } showName("Julio", "César", "Cónsul", "Imperador");
El resto de parámetros deben estar al final.
Los parámetros restantes reúnen todos los argumentos restantes, por lo que lo siguiente no tiene sentido y provoca un error:
function f(arg1, ...descanso, arg2) { // arg2 después ...descanso ?! // error }
El ...rest
siempre debe ser el último.
También hay un objeto especial similar a una matriz llamado arguments
que contiene todos los argumentos por su índice.
Por ejemplo:
función mostrarNombre() { alerta (argumentos.longitud); alerta( argumentos[0] ); alerta( argumentos[1] ); // es iterable // for(let arg de argumentos) alert(arg); } // muestra: 2, Julio, César showName("Julio", "César"); // muestra: 1, Ilya, indefinido (sin segundo argumento) mostrarNombre("Ilya");
En la antigüedad, los parámetros de descanso no existían en el lenguaje y el uso arguments
era la única forma de obtener todos los argumentos de la función. Y todavía funciona, lo podemos encontrar en el código antiguo.
Pero la desventaja es que, aunque arguments
son similares a una matriz y son iterables, no es una matriz. No admite métodos de matriz, por lo que no podemos llamar arguments.map(...)
por ejemplo.
Además, siempre contiene todos los argumentos. No podemos capturarlos parcialmente, como hicimos con los parámetros de descanso.
Entonces, cuando necesitamos estas características, se prefieren los parámetros de descanso.
Las funciones de flecha no tienen "arguments"
Si accedemos al objeto arguments
desde una función de flecha, los toma de la función "normal" externa.
He aquí un ejemplo:
función f() { let showArg = () => alerta(argumentos[0]); mostrarArg(); } f(1); // 1
Como recordamos, las funciones de flecha no tienen su propio this
. Ahora sabemos que tampoco tienen el objeto arguments
especiales.
Acabamos de ver cómo obtener una matriz de la lista de parámetros.
Pero a veces necesitamos hacer exactamente lo contrario.
Por ejemplo, hay una función incorporada Math.max que devuelve el mayor número de una lista:
alerta( Math.max(3, 5, 1) ); // 5
Ahora digamos que tenemos una matriz [3, 5, 1]
. ¿Cómo llamamos Math.max
con él?
Pasarlo "tal cual" no funcionará, porque Math.max
espera una lista de argumentos numéricos, no una sola matriz:
sea arr = [3, 5, 1]; alerta (Math.max (arr)); //NaN
Y seguramente no podemos enumerar manualmente los elementos en el código Math.max(arr[0], arr[1], arr[2])
, porque es posible que no estemos seguros de cuántos hay. A medida que se ejecuta nuestro script, puede haber muchos o puede que no haya ninguno. Y eso se pondría feo.
¡Difunde la sintaxis al rescate! Se parece a los parámetros de descanso, y también usa ...
, pero hace todo lo contrario.
Cuando se usa ...arr
en la llamada a la función, "expande" un objeto iterable arr
en la lista de argumentos.
Para Math.max
:
sea arr = [3, 5, 1]; alerta( Math.max(...arr) ); // 5 (la extensión convierte la matriz en una lista de argumentos)
También podemos pasar múltiples iterables de esta manera:
sea arr1 = [1, -2, 3, 4]; sea arr2 = [8, 3, -8, 1]; alerta( Math.max(...arr1, ...arr2) ); // 8
Incluso podemos combinar la sintaxis extendida con valores normales:
sea arr1 = [1, -2, 3, 4]; sea arr2 = [8, 3, -8, 1]; alerta( Math.max(1, ...arr1, 2, ...arr2, 25) ); // 25
Además, la sintaxis extendida se puede utilizar para fusionar matrices:
sea arr = [3, 5, 1]; sea arr2 = [8, 9, 15]; dejar fusionado = [0, ...arr, 2, ...arr2]; alerta (fusionada); // 0,3,5,1,2,8,9,15 (0, luego arr, luego 2, luego arr2)
En los ejemplos anteriores utilizamos una matriz para demostrar la sintaxis extendida, pero cualquier iterable servirá.
Por ejemplo, aquí usamos la sintaxis extendida para convertir la cadena en una matriz de caracteres:
let str = "Hola"; alerta( [...cadena] ); // Hola
La sintaxis extendida utiliza internamente iteradores para reunir elementos, de la misma manera que lo hace for..of
.
Entonces, para una cadena, for..of
devuelve caracteres y ...str
se convierte en "H","e","l","l","o"
. La lista de caracteres se pasa al inicializador de matriz [...str]
.
Para esta tarea en particular también podríamos usar Array.from
, porque convierte un iterable (como una cadena) en una matriz:
let str = "Hola"; // Array.from convierte un iterable en una matriz alerta (Array.from (str)); // Hola
El resultado es el mismo que [...str]
.
Pero hay una diferencia sutil entre Array.from(obj)
y [...obj]
:
Array.from
opera tanto en tipos de matrices como en iterables.
La sintaxis extendida solo funciona con iterables.
Entonces, para la tarea de convertir algo en una matriz, Array.from
tiende a ser más universal.
¿Recuerdas cuando hablamos de Object.assign()
en el pasado?
Es posible hacer lo mismo con la sintaxis extendida.
sea arr = [1, 2, 3]; let arrCopy = [...arr]; // distribuye la matriz en una lista de parámetros // luego ponemos el resultado en una nueva matriz // ¿las matrices tienen el mismo contenido? alerta(JSON.stringify(arr) === JSON.stringify(arrCopy)); // verdadero // ¿las matrices son iguales? alerta(arr === arrCopy); // falso (no es la misma referencia) // modificar nuestro array inicial no modifica la copia: arr.push(4); alerta(arr); // 1, 2, 3, 4 alerta(arrCopia); // 1, 2, 3
Tenga en cuenta que es posible hacer lo mismo para hacer una copia de un objeto:
sea obj = { a: 1, b: 2, c: 3 }; let objCopy = {...obj}; // distribuye el objeto en una lista de parámetros // luego devuelve el resultado en un nuevo objeto // ¿los objetos tienen el mismo contenido? alerta(JSON.stringify(obj) === JSON.stringify(objCopy)); // verdadero // ¿son iguales los objetos? alerta(obj === objCopy); // falso (no es la misma referencia) // modificar nuestro objeto inicial no modifica la copia: obj.d = 4; alerta(JSON.stringify(obj)); // {"a":1,"b":2,"c":3,"d":4} alerta(JSON.stringify(objCopy)); // {"a":1,"b":2,"c":3}
Esta forma de copiar un objeto es mucho más corta que let objCopy = Object.assign({}, obj)
o para una matriz let arrCopy = Object.assign([], arr)
por lo que preferimos usarla siempre que podamos.
Cuando vemos "..."
en el código, son parámetros de descanso o la sintaxis extendida.
Hay una manera fácil de distinguirlos:
Cuando ...
está al final de los parámetros de la función, son "parámetros restantes" y reúne el resto de la lista de argumentos en una matriz.
Cuando ...
ocurre en una llamada de función o similar, se llama "sintaxis extendida" y expande una matriz en una lista.
Utilice patrones:
Los parámetros de descanso se utilizan para crear funciones que acepten cualquier número de argumentos.
La sintaxis extendida se utiliza para pasar una matriz a funciones que normalmente requieren una lista de muchos argumentos.
Juntos ayudan a viajar entre una lista y una serie de parámetros con facilidad.
Todos los argumentos de una llamada a función también están disponibles en arguments
"antiguos": objeto iterable similar a una matriz.