Skip to content

Update article.md #157

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
188 changes: 116 additions & 72 deletions 1-js/06-advanced-functions/02-rest-parameters-spread-operator/article.md
Original file line number Diff line number Diff line change
@@ -1,20 +1,20 @@
# Rest parameters and spread operator
# 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, more importantly, how to feel comfortable working with such functions and arrays.
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 parameters can be mentioned in a function definition with three dots `...`. They 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,55 +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, no matter their total number.
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.

And it still works, we can use it today.
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(...)`.

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.
Además, siempre contiene todos los argumentos. No podemos capturarlos parcialmente, como hicimos con los parámetros rest.

Also, it always contains all arguments. We can't capture them partially, like we did with rest parameters.

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 @@ -119,25 +117,26 @@ function f() {

f(1); // 1
```

Como recordamos, las arrow functions no tienen su propio `this`. Ahora sabemos que tampoco tienen el objeto especial `arguments`.
````

As we remember, arrow functions don't have their own `this`. Now we know they don't have the special `arguments` object either.

## Spread operator [#spread-operator]
## 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 @@ -147,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 operator* 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 @@ -170,7 +169,7 @@ let arr2 = [8, 3, -8, 1];
alert( Math.max(...arr1, ...arr2) ); // 8
```

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


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

Also, the spread operator 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 @@ -190,56 +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 operator, 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 operator 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 operator 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]`.

Pero hay una sutil diferencia entre `Array.from(obj)` y `[...obj]`:

- `Array.from` opera en ambos, arrays e iterables
- El spread syntax solo funciona con iterables.

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

Recuerdas cuando hablamos sobre `Object.assign()` [en el pasado](https://javascript.info/object#cloning-and-merging-object-assign)?

¡Es posible hacer lo mismo con el operador spread!


```js run
let arr = [1, 2, 3];
let arrCopy = [...arr]; // difunde el array en una lista de parámetros
// luego coloca el resultado en un nuevo array

// ¿Los Arrays tienen el mismo contenido?
alert(JSON.stringify(arr) === JSON.stringify(arrCopy)); // true

// ¿Los arrays son iguales?
alert(arr === arrCopy); // false (no es la misma referencia)

// Modificar nuestro array inicial no modifica la copia:
arr.push(4);
alert(arr); // 1, 2, 3, 4
alert(arrCopy); // 1, 2, 3
```

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 }; // difunde el array en una lista de parámetros
// luego coloca el resultado en un nuevo array

But there's a subtle difference between `Array.from(obj)` and `[...obj]`:
// ¿Los objetos tienen el mismo contenido?
alert(JSON.stringify(obj) === JSON.stringify(objCopy)); // true

- `Array.from` operates on both array-likes and iterables.
- The spread operator operates only on iterables.
// ¿Son iguales los objetos?
alert(obj === objCopy); // false (no es la misma referencia)

// 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}
```

So, for the task of turning something into an array, `Array.from` tends to be more universal.
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 operator.
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 operator" 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 operator 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.