- Notifications
You must be signed in to change notification settings - Fork230
Iterables#179
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 ourterms of service andprivacy statement. We’ll occasionally send you account related emails.
Already on GitHub?Sign in to your account
Merged
Uh oh!
There was an error while loading.Please reload this page.
Merged
Iterables#179
Changes fromall commits
Commits
Show all changes
33 commits Select commitHold shift + click to select a range
eaf6a17
iterable
vplentinaxee6ea60
Merge branch 'master' into iterable
vplentinax2a82824
Update 1-js/05-data-types/06-iterable/article.md
vplentinaxd1f3421
Update 1-js/05-data-types/06-iterable/article.md
vplentinax2c53a7c
Update 1-js/05-data-types/06-iterable/article.md
vplentinaxe8d01b6
Update 1-js/05-data-types/06-iterable/article.md
vplentinaxe293868
Update 1-js/05-data-types/06-iterable/article.md
vplentinaxe486340
Update 1-js/05-data-types/06-iterable/article.md
vplentinaxa338457
Update 1-js/05-data-types/06-iterable/article.md
vplentinaxf9c49f6
Update 1-js/05-data-types/06-iterable/article.md
vplentinaxaeb5652
Update 1-js/05-data-types/06-iterable/article.md
vplentinax37f2a5c
Update 1-js/05-data-types/06-iterable/article.md
vplentinaxb69ef65
Update 1-js/05-data-types/06-iterable/article.md
vplentinaxd2abc4d
Update 1-js/05-data-types/06-iterable/article.md
vplentinax95769e8
Update 1-js/05-data-types/06-iterable/article.md
vplentinaxd6c10f7
Update 1-js/05-data-types/06-iterable/article.md
vplentinax4050994
Update 1-js/05-data-types/06-iterable/article.md
vplentinax63134c7
Update 1-js/05-data-types/06-iterable/article.md
vplentinax42dde7c
Update 1-js/05-data-types/06-iterable/article.md
vplentinax6231593
Update 1-js/05-data-types/06-iterable/article.md
vplentinaxa61b486
Update 1-js/05-data-types/06-iterable/article.md
vplentinaxfe3a79c
Update 1-js/05-data-types/06-iterable/article.md
vplentinax2c8d959
Update 1-js/05-data-types/06-iterable/article.md
vplentinax7905032
Update 1-js/05-data-types/06-iterable/article.md
vplentinaxa195f98
Update 1-js/05-data-types/06-iterable/article.md
vplentinax2cf55ac
Update 1-js/05-data-types/06-iterable/article.md
vplentinaxf41c3d8
Update 1-js/05-data-types/06-iterable/article.md
vplentinax66c34e0
Update 1-js/05-data-types/06-iterable/article.md
vplentinax9423df1
Update 1-js/05-data-types/06-iterable/article.md
vplentinaxa89b9c3
Update 1-js/05-data-types/06-iterable/article.md
vplentinax65a4631
Update 1-js/05-data-types/06-iterable/article.md
vplentinax2639caa
Update 1-js/05-data-types/06-iterable/article.md
vplentinax36b0d08
Update article.md
vplentinaxFile filter
Filter by extension
Conversations
Failed to load comments.
Loading
Uh oh!
There was an error while loading.Please reload this page.
Jump to
Jump to file
Failed to load files.
Loading
Uh oh!
There was an error while loading.Please reload this page.
Diff view
Diff view
There are no files selected for viewing
201 changes: 102 additions & 99 deletions1-js/05-data-types/06-iterable/article.md
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,58 +1,58 @@ | ||
# Iterables | ||
Los objetos *iterables* son una generalización de matrices. Este es un concepto que permite que cualquier objeto pueda ser utilizado en un blucle`for..of`. | ||
Por supuesto, las matrices o *arrays* son iterables. Pero hay muchos otros objetos integrados, que también lo son. Por ejemplo, las cadenas o *strings* son iterables también. Como veremos, muchos operadores y métodos se basan en la iterabilidad. | ||
Si un objeto no es técnicamente una matriz, pero representa una colección (lista, conjunto) de algo, entonces el uso de la sintaxis `for..of` es una gran forma de recorrerlo, así que veamos cómo funciona. | ||
## Symbol.iterator | ||
Podemos comprender fácilmente el concepto de iterables por medio de la práctica. | ||
Por ejemplo, tenemos un objeto, que no es una matriz, pero parece adecuado para `for..of`. | ||
Como un objeto`range`que representa un intervalo de números: | ||
```js | ||
let range = { | ||
from: 1, | ||
to: 5 | ||
}; | ||
//Queremos que el for..offuncione de la siguiente manera: | ||
// for(let num of range) ... num=1,2,3,4,5 | ||
``` | ||
Para hacer que el `range` sea iterable (y así permitir que `for..of` funcione) necesitamos agregar un método al objeto llamado `Symbol.iterator` (un símbolo incorporado especial usado solo para realizar esa función, proporcionar iterabilidad). | ||
1. Cuando se inicia el `for..of`, éste llama al método `Symbol.iterator` una vez (o genera un error si no lo encuentra). El método debe devolver un *iterador* --un objeto con el método `next()`. | ||
2. En adelante, `for..of` trabaja *solo con ese objeto devuelto*. | ||
3. Cuando `for..of` quiere el siguiente valor, llama a `next()` en ese objeto. | ||
4.El resultado de `next()` debe tener la forma `{done: Boolean, value: any}`, donde `done = true` significa que la iteración ha finalizado; de lo contrario,`value` debe ser el nuevo valor. | ||
Aquí está la implementación completa de `range`: | ||
```js run | ||
let range = { | ||
from: 1, | ||
to: 5 | ||
}; | ||
// 1.Una llamada afor..ofinicializa una llamada a esto: | ||
range[Symbol.iterator] = function() { | ||
// ... devuelve el objeto iterador: | ||
// 2.En adelante, for..oftrabaja solo con este iterador, pidiéndole los siguientes valores | ||
return { | ||
current: this.from, | ||
last: this.to, | ||
// 3. next()es llamado en cada iteración por el buclefor..of | ||
next() { | ||
// 4.debería devolver el valor como un objeto {done:.., value :...} | ||
if (this.current <= this.last) { | ||
return { done: false, value: this.current++ }; | ||
} else { | ||
@@ -62,22 +62,22 @@ range[Symbol.iterator] = function() { | ||
}; | ||
}; | ||
//¡Ahora funciona! | ||
for (let num of range) { | ||
alert(num); // 1, then 2, 3, 4, 5 | ||
} | ||
``` | ||
Tenga en cuenta la característica principal de lositerables:separación de conceptos. | ||
-El `range`en sí mismo no tiene el método`next()`. | ||
-En cambio, la llamada a `range[Symbol.iterator]()` crea un otro objeto llamado "iterador", y su `next()`genera valores para la iteración. | ||
Por lo tanto, el objeto iterador está separado del objeto sobre el que itera. | ||
Técnicamente, podemos fusionarlos y usar`range`en sí mismo como iterador para simplificar el código. | ||
De esta manera: | ||
```js run | ||
let range = { | ||
@@ -103,51 +103,51 @@ for (let num of range) { | ||
} | ||
``` | ||
Ahora `range[Symbol.iterator]()`devuelve el objeto`range`en sí: tiene el método`next()`necesario y recuerda el progreso de iteración actual en`this.current`.¿Más corto? Sí. Y a veces eso también está bien. | ||
La desventaja es que ahora es imposible tener dos bucles `for..of` corriendo sobre el objeto simultáneamente: compartirán el estado de iteración, porque solo hay un iterador: el objeto en sí. Pero dos for-ofs paralelos es algo raro, incluso en escenarios asíncronos. | ||
```smart header="Iteradores Infinitos" | ||
También son posibles los iteradores infinitos. Por ejemplo, el objeto `range` se vuelve infinito así: `range.to = Infinity`. O podemos hacer un objeto iterable que genere una secuencia infinita de números pseudoaleatorios. También puede ser útil. | ||
No hay limitaciones en `next`, puede devolver más y más valores, eso es normal. | ||
Por supuesto, el bucle `for..of` sobre un iterable de este tipo sería interminable. Pero siempre podemos detenerlo usando `break`. | ||
``` | ||
## *String* es iterable | ||
Las matrices y cadenas son los iterables integrados más utilizados. | ||
En una cadena o *string*, el bucle`for..of`recorre sus caracteres: | ||
```js run | ||
for (let char of "test") { | ||
//Se dispara 4 veces: una vez por cada caracter | ||
alert( char ); // t,luego e,luego s,luego t | ||
} | ||
``` | ||
¡Y trabaja correctamente con valores de pares sustitutos (codificación UTF-16)! | ||
```js run | ||
let str = '𝒳😂'; | ||
for (let char of str) { | ||
alert( char ); // 𝒳,y luego 😂 | ||
} | ||
``` | ||
##Llamar a un iterador explícitamente | ||
vplentinax marked this conversation as resolved. Show resolvedHide resolvedUh oh!There was an error while loading.Please reload this page. | ||
Para una comprensión más profunda, veamos cómo usar un iterador explícitamente. | ||
Vamos a iterar sobre una cadena exactamente de la misma manera que`for..of`,pero con llamadas directas. Este código crea un iterador de cadena y obtiene valores de él "manualmente": | ||
```js run | ||
let str = "Hola"; | ||
//hace lo mismo que | ||
// for (let char of str) alert(char); | ||
*!* | ||
@@ -157,92 +157,93 @@ let iterator = str[Symbol.iterator](); | ||
while (true) { | ||
let result = iterator.next(); | ||
if (result.done) break; | ||
alert(result.value); //retorna los caracteres uno por uno | ||
} | ||
``` | ||
Rara vez se necesita esto, pero nos da más control sobre el proceso que `for..of`. Por ejemplo, podemos dividir el proceso de iteración: iterar un poco, luego parar, hacer otra cosa y luego continuar. | ||
## Iterables y array-likes [#array-like] | ||
Hay dos términos oficiales que se parecen, pero son muy diferentes. Asegúrese de comprenderlos bien para evitar confusiones. | ||
- *Iterables* son objetos que implementan el método `Symbol.iterator`, como se describió anteriormente. | ||
- *Array-likes* son objetos que tienen índices y `longitud` o *length*, por lo que se ven como matrices. | ||
Cuando usamos JavaScript para tareas prácticas en el navegador u otros entornos, podemos encontrar objetos que son iterables oarray-like, o ambos. | ||
Por ejemplo, las cadenas son iterables (`for..of` funciona en ellas) y array-like (tienen índices numéricos y `length`). | ||
Pero un iterable puede no ser array-like. Y viceversa, un array-like puede no ser iterable. | ||
Por ejemplo, `range` en el ejemplo anterior es iterable, pero no array-like, porque no tiene propiedades indexadas ni `longitud` o *length*. | ||
Y aquí está el objeto que tiene forma de matriz, pero no es iterable: | ||
vplentinax marked this conversation as resolved. Show resolvedHide resolvedUh oh!There was an error while loading.Please reload this page. | ||
```js run | ||
let arrayLike = { //tiene índices y longitud => array-like | ||
0: "Hola", | ||
1: "Mundo", | ||
length: 2 | ||
}; | ||
*!* | ||
// Error (sin Symbol.iterator) | ||
for (let item of arrayLike) {} | ||
*/!* | ||
``` | ||
Tanto lositerablescomo losarray-like generalmente no son *matrices*, no tienen "push", "pop", etc.Eso es bastante inconveniente si tenemos un objeto de este tipo y queremos trabajar con él como con una matriz. P.ej. nos gustaría trabajar con`range`utilizando métodos de matriz. ¿Cómo lograr eso? | ||
## Array.from | ||
Existe un métodouniversal [Array.from](https://developer.mozilla.org/es/docs/Web/JavaScript/Referencia/Objetos_globales/Array/from)que toma un valoriterableo similar a una matriz y crea un`Array`¨real¨ a partir de él. De esta manera podemos llamar y usar métodos que pertenecen a una matriz. | ||
Por ejemplo: | ||
```js run | ||
let arrayLike = { | ||
0: "Hola", | ||
1: "Mundo", | ||
length: 2 | ||
}; | ||
*!* | ||
let arr = Array.from(arrayLike); // (*) | ||
*/!* | ||
alert(arr.pop()); //Mundo (el método pop funciona) | ||
``` | ||
`Array.from`en la línea `(*)`toma el objeto, lo examina por seriterableo similar a una matriz, luego crea una nueva matriz y copia allí todos los elementos. | ||
Lo mismo sucede para un iterable: | ||
```js | ||
//suponiendo que rangese toma del ejemplo anterior | ||
let arr = Array.from(range); | ||
alert(arr); // 1,2,3,4,5 (la conversión de matriz a cadena funciona) | ||
``` | ||
La sintaxis completa para `Array.from`también nos permite proporcionar una función opcional de "mapeo": | ||
```js | ||
Array.from(obj[, mapFn, thisArg]) | ||
``` | ||
El segundo argumento opcional `mapFn`puede ser una función que se aplicará a cada elemento antes de agregarlo a la matriz, y `thisArg`permite establecer el`this`para ello. | ||
Por ejemplo: | ||
```js | ||
//suponiendo que rangese toma del ejemplo anterior | ||
//el cuadrado de cada número | ||
let arr = Array.from(range, num => num * num); | ||
alert(arr); // 1,4,9,16,25 | ||
``` | ||
Aquí usamos`Array.from`para convertir una cadena en una matriz de caracteres: | ||
```js run | ||
let str = '𝒳😂'; | ||
@@ -255,24 +256,25 @@ alert(chars[1]); // 😂 | ||
alert(chars.length); // 2 | ||
``` | ||
A diferencia de `str.split`, `Array.from` se basa en la naturaleza iterable de la cadena y, por lo tanto, al igual que `for..of`, funciona correctamente con pares sustitutos. | ||
Técnicamente aquí hace lo mismo que: | ||
```js run | ||
let str = '𝒳😂'; | ||
let chars = []; // Array.from internamente hace el mismo bucle | ||
for (let char of str) { | ||
chars.push(char); | ||
} | ||
alert(chars); | ||
``` | ||
... Pero es más corto. | ||
Incluso podemos construir un `segmento` o`slice`compatible con sustitutos en él: | ||
```js run | ||
function slice(str, start, end) { | ||
@@ -283,25 +285,26 @@ let str = '𝒳😂𩷶'; | ||
alert( slice(str, 1, 3) ); // 😂𩷶 | ||
//el método nativo no admite pares sustitutos | ||
alert( str.slice(1, 3) ); // garbage (dos piezas de diferentes pares sustitutos) | ||
``` | ||
## Resumen | ||
Los objetos que se pueden usar en `for..of` se denominan *iterables*. | ||
- Técnicamente, los iterables deben implementar el método llamado `Symbol.iterator`. | ||
- El resultado de `obj[Symbol.iterator]` se llama *iterador*. Maneja el proceso de iteración adicional. | ||
- Un iterador debe tener el método llamado `next()` que devuelve un objeto `{done: Boolean, value: any}`, donde `done: true` denota el final de la iteración, de lo contrario, `value` es el siguiente valor. | ||
- El método `Symbol.iterator` se llama automáticamente por `for..of`, pero también podemos hacerlo directamente. | ||
- Los iterables integrados, como cadenas o matrices, también implementan `Symbol.iterator`. | ||
- El iterador de cadena funciona con pares sustitutos. | ||
Los objetos que tienen propiedades indexadas y `longitud` o *length* se llaman*array-like*.Dichos objetos también pueden tener otras propiedades y métodos, pero carecen de los métodos integrados de las matrices. | ||
Si miramos dentro de la especificación, veremos que la mayoría de los métodos incorporados suponen que funcionan con iterableso array-likesen lugar de matrices "reales", porque eso es más abstracto. | ||
`Array.from (obj[, mapFn, thisArg])` crea un verdadero `Array` de un `obj` iterable o array-like, y luego podemos usar métodos de matriz en él. Los argumentos opcionales `mapFn` y `thisArg` nos permiten aplicar una función a cada elemento. | ||
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.