Skip to content

Rest parameters and spread syntax #261

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 1 commit into from
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
172 changes: 86 additions & 86 deletions 1-js/06-advanced-functions/02-rest-parameters-spread/article.md
Original file line number Diff line number Diff line change
@@ -1,20 +1,20 @@
# Rest parameters and spread syntax
# Parámetros Rest y spread syntax

Many JavaScript built-in functions support an arbitrary number of arguments.
Muchas funciones incorporadas de JavaScript admiten una cantidad arbitraria de argumentos.

For instance:
Por ejemplo:

- `Math.max(arg1, arg2, ..., argN)` -- returns the greatest of the arguments.
- `Object.assign(dest, src1, ..., srcN)` -- copies properties from `src1..N` into `dest`.
- ...and so on.
- `Math.max(arg1, arg2, ..., argN)` -- devuelve el mayor de los argumentos.
- `Object.assign(dest, src1, ..., srcN)` -- copia propiedades desde `src1..N` a `dest`.
- ...y así.

In this chapter we'll learn how to do the same. And also, how to pass arrays to such functions as parameters.
En este capítulo aprenderemos cómo hacer lo mismo. Y también, cómo pasar Arrays a funciones tales como parámetros.

## Rest parameters `...`
## Parámetros rest `...`

A function can be called with any number of arguments, no matter how it is defined.
Se puede llamar a una función con cualquier número de argumentos, sin importar cómo se defina.

Like here:
Como aquí:
```js run
function sum(a, b) {
return a + b;
Expand All @@ -23,14 +23,14 @@ function sum(a, b) {
alert( sum(1, 2, 3, 4, 5) );
```

There will be no error because of "excessive" arguments. But of course in the result only the first two will be counted.
No habrá errores debido a argumentos "excesivos". Pero, por supuesto, en el resultado solo se contarán los dos primeros.

The rest of the parameters can be included in the function definition by using three dots `...` followed by the name of the array that will contain them. The dots literally mean "gather the remaining parameters into an array".
El resto de los parámetros se pueden incluir en la definición de la función utilizando tres puntos `...` seguidos del nombre del array que los contendrá. Los puntos literalmente significan "reunir los parámetros restantes en un Array".

For instance, to gather all arguments into array `args`:
Por ejemplo, para reunir todos los argumentos en el array `args`:

```js run
function sumAll(...args) { // args is the name for the array
function sumAll(...args) { // args es el mismo para el array
let sum = 0;

for (let arg of args) sum += arg;
Expand All @@ -43,16 +43,16 @@ alert( sumAll(1, 2) ); // 3
alert( sumAll(1, 2, 3) ); // 6
```

We can choose to get the first parameters as variables, and gather only the rest.
Podemos elegir obtener los primeros parámetros como variables y luego reunir solo el resto.

Here the first two arguments go into variables and the rest go into `titles` array:
Aquí los dos primeros argumentos van a las variables y el resto va el array `titles`:

```js run
function showName(firstName, lastName, ...titles) {
alert( firstName + ' ' + lastName ); // Julius Caesar

// the rest go into titles array
// i.e. titles = ["Consul", "Imperator"]
// el resto va a el array titles:
// ej: titles = ["Consul", "Imperator"]
alert( titles[0] ); // Consul
alert( titles[1] ); // Imperator
alert( titles.length ); // 2
Expand All @@ -61,53 +61,53 @@ function showName(firstName, lastName, ...titles) {
showName("Julius", "Caesar", "Consul", "Imperator");
```

````warn header="The rest parameters must be at the end"
The rest parameters gather all remaining arguments, so the following does not make sense and causes an error:
````warn header="Los parámetros rest deben estar al final"
Los parámetros rest recopilan todos los argumentos restantes, por lo que lo siguiente no tiene sentido y causa un error:

```js
function f(arg1, ...rest, arg2) { // arg2 after ...rest ?!
// error
}
```

The `...rest` must always be last.
El parámetro `...rest` siempre debe ser último.
````

## The "arguments" variable
## La variable "argumentos"

There is also a special array-like object named `arguments` that contains all arguments by their index.
También hay un objeto especial tipo array llamado `arguments` que contiene todos los argumentos por su índice.

For instance:
Por ejemplo:

```js run
function showName() {
alert( arguments.length );
alert( arguments[0] );
alert( arguments[1] );

// it's iterable
// Es iterable
// for(let arg of arguments) alert(arg);
}

// shows: 2, Julius, Caesar
// muestra: 2, Julius, Caesar
showName("Julius", "Caesar");

// shows: 1, Ilya, undefined (no second argument)
// muestra: 1, Ilya, undefined (No hay segundo argumento)
showName("Ilya");
```

In old times, rest parameters did not exist in the language, and using `arguments` was the only way to get all arguments of the function. And it still works, we can find it in the old code.
En los viejos tiempos, los *parámetros rest* no existían en el lenguaje, y el uso de `arguments` era la única forma de obtener todos los argumentos de la función. Y aún funciona, podemos encontrarlo en el código anterior.

But the downside is that although `arguments` is both array-like and iterable, it's not an array. It does not support array methods, so we can't call `arguments.map(...)` for example.
Pero la desventaja es que aunque los `arguments` son a la vez como un Array e iterables, no es un Array. No admite métodos Array, por lo que no podemos llamar a `arguments.map(...)`.

Also, it always contains all arguments. We can't capture them partially, like we did with rest parameters.
Además, siempre contiene todos los argumentos. No podemos capturarlos parcialmente, como hicimos con los parámetros rest.

So when we need these features, then rest parameters are preferred.
Entonces, cuando necesitamos estas características, se prefieren los parámetros rest.

````smart header="Arrow functions do not have `\"arguments\"`"
If we access the `arguments` object from an arrow function, it takes them from the outer "normal" function.
Si accedemos al objeto `arguments` desde una arrow function, los toma desde la función "normal" externa.

Here's an example:
Aquí hay un ejemplo:

```js run
function f() {
Expand All @@ -118,25 +118,25 @@ function f() {
f(1); // 1
```

As we remember, arrow functions don't have their own `this`. Now we know they don't have the special `arguments` object either.
Como recordamos, las arrow functions no tienen su propio `this`. Ahora sabemos que tampoco tienen el objeto especial `arguments`.
````


## Spread syntax [#spread-syntax]

We've just seen how to get an array from the list of parameters.
Acabamos de ver cómo obtener un Array de la lista de parámetros.

But sometimes we need to do exactly the reverse.
Pero a veces necesitamos hacer exactamente lo contrario.

For instance, there's a built-in function [Math.max](mdn:js/Math/max) that returns the greatest number from a list:
Por ejemplo, hay una función incorporada [Math.max](mdn:js/Math/max) que devuelve el mayor número de una lista:

```js run
alert( Math.max(3, 5, 1) ); // 5
```

Now let's say we have an array `[3, 5, 1]`. How do we call `Math.max` with it?
Ahora digamos que tenemos Array `[3, 5, 1]`. ¿Cómo llamamos a `Math.max` con él?

Passing it "as is" won't work, because `Math.max` expects a list of numeric arguments, not a single array:
Pasarlo "como está" no funcionará, porque `Math.max` espera una lista de argumentos numéricos, no un solo Array:

```js run
let arr = [3, 5, 1];
Expand All @@ -146,21 +146,21 @@ alert( Math.max(arr) ); // NaN
*/!*
```

And surely we can't manually list items in the code `Math.max(arr[0], arr[1], arr[2])`, because we may be unsure how many there are. As our script executes, there could be a lot, or there could be none. And that would get ugly.
Y seguramente no podemos enumerar manualmente los elementos en el código `Math.max(arr [0], arr [1], arr [2])`, porque podemos no estar seguros de cuántos hay. A medida que se ejecuta nuestro script, podrían haber muchos o no podría haber ninguno. Y eso se pondría feo.

*Spread syntax* to the rescue! It looks similar to rest parameters, also using `...`, but does quite the opposite.
*Spread syntax* al rescate! Se ve similar a los parámetros rest, también usando `...`, pero hace todo lo contrario.

When `...arr` is used in the function call, it "expands" an iterable object `arr` into the list of arguments.
Cuando se usa `... arr` en la llamada a la función, "expande" un objeto iterable `arr` en la lista de argumentos.

For `Math.max`:
Para `Math.max`:

```js run
let arr = [3, 5, 1];

alert( Math.max(...arr) ); // 5 (spread turns array into a list of arguments)
alert( Math.max(...arr) ); // 5 (spread convierte el Array en una lista de argumentos)
```

We also can pass multiple iterables this way:
También podemos pasar múltiples iterables de esta manera:

```js run
let arr1 = [1, -2, 3, 4];
Expand All @@ -169,7 +169,7 @@ let arr2 = [8, 3, -8, 1];
alert( Math.max(...arr1, ...arr2) ); // 8
```

We can even combine the spread syntax with normal values:
Incluso podemos combinar spread syntax con valores normales:


```js run
Expand All @@ -179,7 +179,7 @@ let arr2 = [8, 3, -8, 1];
alert( Math.max(1, ...arr1, 2, ...arr2, 25) ); // 25
```

Also, the spread syntax can be used to merge arrays:
Además, spread syntax se puede utilizar para fusionar Arrays:

```js run
let arr = [3, 5, 1];
Expand All @@ -189,101 +189,101 @@ let arr2 = [8, 9, 15];
let merged = [0, ...arr, 2, ...arr2];
*/!*

alert(merged); // 0,3,5,1,2,8,9,15 (0, then arr, then 2, then arr2)
alert(merged); // 0,3,5,1,2,8,9,15 (0, luego arr, luego 2, luego arr2)
```

In the examples above we used an array to demonstrate the spread syntax, but any iterable will do.
En los ejemplos anteriores, utilizamos un Array para demostrar spread syntax, pero cualquier iterable funcionará.

For instance, here we use the spread syntax to turn the string into array of characters:
Por ejemplo, aquí usamos spread syntax para convertir la cadena en un Array de caracteres:

```js run
let str = "Hello";

alert( [...str] ); // H,e,l,l,o
```

The spread syntax internally uses iterators to gather elements, the same way as `for..of` does.
Spread syntax utiliza internamente iteradores para reunir elementos, de la misma manera que lo hace `for..of`.

So, for a string, `for..of` returns characters and `...str` becomes `"H","e","l","l","o"`. The list of characters is passed to array initializer `[...str]`.
Entonces, para un string, `for..of` devuelve caracteres y `...str` se convierte en `"H","e","l","l","o"`. La lista de caracteres se pasa al inicializador de array `[...str]`.

For this particular task we could also use `Array.from`, because it converts an iterable (like a string) into an array:
Para esta tarea en particular también podríamos usar `Array.from`, porque convierte un iterable (como un string) en un Array:

```js run
let str = "Hello";

// Array.from converts an iterable into an array
// Array.from convierte un iterable en un array
alert( Array.from(str) ); // H,e,l,l,o
```

The result is the same as `[...str]`.
El resultado es el mismo que `[...str]`.

But there's a subtle difference between `Array.from(obj)` and `[...obj]`:
Pero hay una sutil diferencia entre `Array.from(obj)` y `[...obj]`:

- `Array.from` operates on both array-likes and iterables.
- The spread syntax works only with iterables.
- `Array.from` opera en ambos, arrays e iterables
- El spread syntax solo funciona con iterables.

So, for the task of turning something into an array, `Array.from` tends to be more universal.
Entonces, para la tarea de convertir algo en un array, `Array.from` tiende a ser más universal.

## Obtener una nueva copia de un objeto/array

## Get a new copy of an array/object
Recuerdas cuando hablamos sobre `Object.assign()` [en el pasado](https://javascript.info/object#cloning-and-merging-object-assign)?

Remember when we talked about `Object.assign()` [in the past](https://javascript.info/object#cloning-and-merging-object-assign)?
¡Es posible hacer lo mismo con el operador spread!

It is possible to do the same thing with the spread syntax.

```js run
let arr = [1, 2, 3];
let arrCopy = [...arr]; // spread the array into a list of parameters
// then put the result into a new array
let arrCopy = [...arr]; // difunde el array en una lista de parámetros
// luego coloca el resultado en un nuevo array

// do the arrays have the same contents?
// ¿Los Arrays tienen el mismo contenido?
alert(JSON.stringify(arr) === JSON.stringify(arrCopy)); // true

// are the arrays equal?
alert(arr === arrCopy); // false (not same reference)
// ¿Los arrays son iguales?
alert(arr === arrCopy); // false (no es la misma referencia)

// modifying our initial array does not modify the copy:
// Modificar nuestro array inicial no modifica la copia:
arr.push(4);
alert(arr); // 1, 2, 3, 4
alert(arrCopy); // 1, 2, 3
```

Note that it is possible to do the same thing to make a copy of an object:
Tenga en cuenta que es posible hacer lo mismo para hacer una copia de un objeto:

```js run
let obj = { a: 1, b: 2, c: 3 };
let objCopy = { ...obj }; // spread the object into a list of parameters
// then return the result in a new object
let objCopy = { ...obj }; // difunde el array en una lista de parámetros
// luego coloca el resultado en un nuevo array

// do the objects have the same contents?
// ¿Los objetos tienen el mismo contenido?
alert(JSON.stringify(obj) === JSON.stringify(objCopy)); // true

// are the objects equal?
alert(obj === objCopy); // false (not same reference)
// ¿Son iguales los objetos?
alert(obj === objCopy); // false (no es la misma referencia)

// modifying our initial object does not modify the copy:
// La modificación de nuestro objeto inicial no modifica la copia:
obj.d = 4;
alert(JSON.stringify(obj)); // {"a":1,"b":2,"c":3,"d":4}
alert(JSON.stringify(objCopy)); // {"a":1,"b":2,"c":3}
```

This way of copying an object is much shorter than `let objCopy = Object.assign({}, obj);` or for an array `let arrCopy = Object.assign([], arr);` so we prefer to use it whenever we can.
Esta forma de copiar un objeto es mucho más corta que `let objCopy = Object.assign({}, obj);` o para un array `let arrCopy = Object.assign ([], arr);` por lo que preferimos usarlo siempre que podamos.


## Summary
## Resumen

When we see `"..."` in the code, it is either rest parameters or the spread syntax.
Cuando vemos `" ... "` en el código, se trata de parámetros rest o de spread syntax.

There's an easy way to distinguish between them:
Hay una manera fácil de distinguirlos:

- When `...` is at the end of function parameters, it's "rest parameters" and gathers the rest of the list of arguments into an array.
- When `...` occurs in a function call or alike, it's called a "spread syntax" and expands an array into a list.
- Cuando `...` está al final de los parámetros de la función, se trata de "parámetros rest" y reúne el resto de la lista de argumentos en un array.
- Cuando `...` ocurre en una llamada de función o similar, se llama "spread syntax" y expande un array en una lista.

Use patterns:
Usar patrones:

- Rest parameters are used to create functions that accept any number of arguments.
- The spread syntax is used to pass an array to functions that normally require a list of many arguments.
- Parámetros rest se utilizan para crear funciones que aceptan cualquier número de argumentos.
- Spread syntax se utiliza para pasar un array a funciones que normalmente requieren una lista de muchos argumentos.

Together they help to travel between a list and an array of parameters with ease.
Juntos ayudan a viajar entre una lista y una variedad de parámetros con facilidad.

All arguments of a function call are also available in "old-style" `arguments`: array-like iterable object.
Todos los argumentos de una llamada a función también están disponibles en el "viejo estilo" `arguments`: objeto iterable tipo array.