JavaScript — Loops

Mauricio Garcia
11 min readDec 7, 2019

--

Temario

  • for
  • for…of
  • for…in
  • while
  • do…while
  • Introducción (II)
  • array.foreach
  • array.find
  • array.findIndex
  • array.some
  • array.every
  • array.map
  • array.filter
  • array.reduce
  • array.reduceRight

Los bucles en JavaScript son pedazos de códigos ejecutados repetidamente cierta cantidad de veces.

i. for

En JavaScript, es el iterador más básico; donde crea un bucle que consiste en tres expresiones encerradas en paréntesis()’ y separadas por puntos y comas ‘;’, seguida de una sentencia ejecutada.

Veamos un ejemplo:

El ejemplo anterior se leería de la siguiente manera:

  1. Inicializamos el contador i = 0 (la mayoría de las veces comienza en 0)
  2. Condición que valida si continúa o se detiene el bucle ( i < 5, mientras se cumpla con esta condición va a ejecutar el código de sentencia, caso contrario detiene el bucle)
  3. Actualiza el contador (incrementa o decrementa) i++
  4. Se repite el paso 2

Ejemplo 2:

ii. for…of

El for…of crea un bucle que itera a través de elementos de objetos iterables (Array, Map, Set, etc), ejecutando la sentencia de cada iteración con el valor del elemento que corresponda.

La ventaja de hacerlo con el for…of es de que no se necesita crear variables de índice y cuando llega al final de la matriz, dejará de repetirse automáticamente.

Ejemplo:

Importante: for…of solo funciona con valores iterables. Por lo tanto, no se puede usar en objetos.

iii. for…in

El for…in itera sobre todos los elementos de un objeto, en un orden arbitrario, ejecutando la sentencia correspondiente.

Este bucle no se recomienda mucho usarlo ya que itera sobre propiedades definidas por el usuario, incluyendo propiedades o métodos añadidos en Array.prototype y además la iteración la hace en un orden arbitrario, por lo que no accede a los elementos en orden numérico, se recomienda usar mejor un for tradicional.

Ejemplo:

iv. while

El bucle while ejecuta una sentencia especificada, mientras la condición sea true va a ejecutar la sentencia, es importante recalcar que la condición es evaluada antes de ejecutar la sentencia.

Este bucle lo ejecutamos cuando queremos hacer un bucleinfinito o hasta que se cumpla una condición específica.

Ejemplo:

v. do…while

El bucle while ejecuta una sentencia especificada, hasta que la condición sea false, es importante recalcar que la condición es evaluada después de ejecutar la sentencia, esto quiere decir que la sentencia se va a ejecutar al menos una vez más después de haber cumplido con la condición.

Este bucle lo ejecutamos cuando queremos hacer un bucle infinito o hasta que se cumpla una condición específica y una más.

Ejemplo:

vi. Introducción (II)

Generalmente cuando aprendemos bucles lo usamos para las matrices Array, lo cual no está mal; pero… ¿sabías que Array tiene métodos propios para iterar objetos?… actualmente lo podemos dividir en dos grupos :

  • Iterables sin devolver una nueva matriz. (foreach, find, findIndex, some, every)
  • Iterables que devuelven una nueva matriz. (map, filter, reduce, reduceRight)

Vamos a ello…

vii. array.foreach

Este método entra dentro del grupo de Iterables sin devolver una nueva matriz, lo que hace el foreach es ejecutar una función por cada elemento del arreglo. En cada iteración se tendrá acceso a 3 variables: valor (del elemento), índice (del elemento) y arreglo (que estamos recorriendo).

Este método es muy útil cuando solo necesitamos ejecutar una función a través de cada elemento del arreglo, sin necesidad de obtener un retorno.

Antes de verlo en acción, veamos un ejemplo con el for:

Con foreach:

Si comparamos el for con el foreach, podemos ver que es más cómodo y limpio usar el foreach, ya que solo invocamos el método foreach, especificamos una función de devolución, donde va a estar iterando y devolviendo cada uno de los elementos y cuando termina, simplemente continúa con la siguiente instrucción.

Recordemos que también podemos declarar una función, veamos el siguiente ejemplo:

Con el método forEach realmente no retorna nada, aunque si podemos mutar la matriz que estamos iterando, solo que no se recomienda, para eso es mejor usar map.

viii. array.find

El método find va a devolver el primer elemento del array que cumpla con la condición dada; si no se cumple nunca la condición, devolverá undefined

Ejemplo :

Veamos otro ejemplo (2):

En el ejemplo de arriba, podemos ver que la condición es element < 3, si vemos el arreglo sabemos que 1, 2 cumplen con dicha condición, pero la regla del find es regresar el primer valor que cumpla con la condición, en este caso 1.

Ejemplo 3:

Para este caso el valor de car es undefined, ya que no ha cumplido con la condición dada.

Veamos un ejemplo (4) con un arreglo de objetos:

No olvidemos que también podemos declarar una función, veamos el ejemplo anterior, ejemplo (5):

ix. array.findIndex

El método findIndex funciona de la misma manera que find, solo que este va a devolver el índice del array que cumpla con la condición dada; si no se cumple nunca la condición, devolverá -1

Ejemplo 1:

Ejemplo 2:

En este ejemplo, podemos ver que la condición es element < 3, si vemos el arreglo sabemos que 1, 2 cumplen con dicha condición, pero la regla del find es regresar el primer índice que cumpla con la condición, en este caso el índice 0.

Ejemplo 3:

Para este caso el valor de car es -1, ya que no ha cumplido con la condición dada.

Veamos un ejemplo (4) con arreglo de objetos:

No olvidemos que también podemos declarar una función, veamos el ejemplo (5):

x. array.some

El método some va a devolver true si la condición dada cumple al menos una vez; si no se cumple nunca la condición, devolverá false.

Ejemplo 1:

Ejemplo 2:

Ejemplo 3:

Para este caso el valor de car es false, ya que no ha cumplido con la condición dada.

Veamos un ejemplo (4) con un arreglo de objetos:

No olvidemos que también podemos declarar una función, veamos el ejemplo (5):

xi. array.every

El método every va a devolver true si TODOS los elementos cumplen la condición dada, si alguno de ellos no cumple regresa false.

Ejemplo 1:

En este ejemplo devuelve false, ya que solo 1, 2, 3, 4 SI cumplen, pero el último al no cumple.

Ejemplo 2:

En este ejemplo devuelve false, ya que TODOS cumplen con la condición dada.

Veamos un ejemplo (3) con un arreglo de objetos:

Hasta ahora hemos visto los métodos que son iterables sin devolver una nueva matriz, vamos a ver los métodos que son iterables que devuelven una nueva matriz.

xii. array.map

El método map, lo utilizamos cuando queremos transformar un arreglo, pero persistiendo el arreglo original, dicho en otras palabras ejecuta una función dada en cada elemento del arreglo actual y crea un nuevo arreglo con el resultado de la función dada.

Muchos desarrolladores llegan a decir que forEach y map son iguales, lo cual no es cierto, ya que :

Ejemplo:

Como podemos observar en el ejemplo anterior, map crea un nuevo arreglo del mismo tamaño que el original.

Ejemplo 2:

Veamos un ejemplo (3) usando map, donde regresamos un nuevo formato en los objetos de un arreglo:

Hay que tener cuidado cuando lo usemos con objetos más complejos, ya que map, solo hace un copiado superficial (shadow copy [ref]), que se ha explicado en el tema anterior.

Veamos un ejemplo(4) con objetos complejos:

Supongamos que tenemos un método getMovies que nos retorna una lista de películas, entonces:

Para nuestro flujo, requerimos agregarle el poster:

Cuando revisamos el arreglo movies y moviesWithPoster :

Podemos observar que el cambio se hizo en ambos arreglos, a pesar de que map crea un nuevo arreglo, los objetos siguen instanciados ya que el clonado de map es a nivel superficial, entonces podemos resolverlo usando Object.assign (Que ya vimos en Shallow Copy and Deep Copy [ref]):

Cuando imprimimos en consola nuestros arreglos movies y moviesWithPoster, podemos observar que nuestro arreglo original ya no se vió afectado por el nuevo cambio.

Ahora supongamos que la propiedad cast, necesitamos agregar un id:

Podemos observar que el cambio se hizo en ambos arreglos, a pesar de que hacemos uso de Object.assign, recordemos que su clonado es a nivel superficial, entonces podemos resolverlo usando JSON.parse y JSON.stringify y con esto haremos un clonado profundo:

Ejemplo 5:

Recuerdan cuando vimos Closures & Currying[ref], les mencioné que íbamos a realizar un ejemplo con map y currying, bueno ha llegado ese momento…

Imaginemos que queremos saber las tablas de multiplicar, entonces, tenemos un arreglo de números [1,2,3,4,5,6,7,8,9,10], quizás la solución más simple sería:

Con el ejemplo anterior realmente solucionamos nuestro problema, pero, en memoria se está mandando a llamar la función 10 veces y además está creando dos valores (n, v) por cada iteración; vamos a hacerle unas pequeñas mejoras (aunque aún no solucionemos nuestro problema)…

Estamos quizás empeorando un poco la parte de memoria, ya que estamos ejecutando el doble de funciones (la primera para recorrer el objeto y la segunda para hacer la multiplicación), pero… la ventaja es de que ya tenemos una función reutilizable (multiplication), con esto nos acercamos un poco más a la programación funcional** ….

Ahora lo que vamos a hacer es especializar nuestra función multiplication de manera correcta, y esto es, volviéndola curry:

Sabemos que podemos llamar nuestra función multiplication con valores unarios (no olvidemos las ventajas que tiene esto en memoria [ref]); entonces solo es cuestión de mandar a llamar en nuestro map la función, con el primer parámetro (en nuestro caso es el valor a multiplicar) e internamente el map se encargará de mandar el segundo parámetro…

Si te das cuenta he cambiado totalmente la forma de llamar a la función, internamente el map si sigue mandando a llamar 10 veces la función, pero solo con un parámetro, por lo que se reduce mucho en memoria…ya que el primer valor que mandamos se persiste, por lo que solo ocupa un solo lugar y no se está creando uno nuevo cada vez que el map ejecuta la función…

Esta forma de programar es muy común en programación funcional**, ya que hacemos el llamado de pequeñas funciones especializadas, que nos da la ventaja de que en cualquier lado podemos utilizarlas y además están optimizadas para ocupar poco espacio en memoria.

Ejemplo 6:

xiii. array.filter

El método filter crea un nuevo arreglo con todos los elementos que cumplan la condición dada, dicho en otras palabras, cuando iteramos un arreglo y queremos seleccionar cada el elemento que cumpla con la condición dada.

En caso de que ninguno cumpla, retorna un arreglo vacío.

Ejemplo 1:

Ejemplo 2:

Veamos un ejemplo(3) usando filter, donde regresamos objetos de un arreglo:

Veamos un ejemplo más, imaginemos que tenemos el siguiente arreglo (personajes de una serie de anime):

Queremos filtrar por grupo:

En consola veríamos lo siguiente:

Bastante sencillo de filtrar ¿no?

Hay que tener cuidado cuando lo usemos con objetos más complejos, ya que filter al igual que map, solo hace un copiado superficial (shadow copy), se ha explicado en el tema anterior.

Ejemplo 5:

xiv. array.reduce

El método reduce también ejecuta una devolución de llamada para que elemento del arreglo, pero como su nombre lo dice reduce a un solo valor el arreglo (puede ser un objeto, string, número, etc.)

Veamos el ejemplo más común, la suma de los números:

En la siguiente imagen podemos ver cada una de las iteraciones que va haciendo reduce al arreglo sum, y como va acumulando accumulator el valor accumulator + currentValue

Veamos otro ejemplo, supongamos que tenemos una lista de todos los empleados de una empresa por país y que además queremos saber cuántos hay en total, pero, sin contar Other

Otro ejemplo más, aprovechemos la lista pasada, supongamos que queremos obtener objeto que más empleados employees tiene.

Hay que tener cuidado cuando lo usemos con objetos más complejos, ya que reduce al igual que map, solo hace un copiado superficial (shadow copy), se ha explicado en el tema anterior.

Ejemplo 4:

xv. array.reduceRight

Funciona exactamente igual que el método reduce, la única diferencia es que itera un arreglo hacia atrás, de derecha a izquierda.

Apliquemos el ejemplo de la suma de números que usamos con reduce, pero ahora con reduceRight y veamos cómo funciona:

En la siguiente imagen podemos ver cada una de las iteraciones que va haciendo reduceRight al arreglo sum, y como va acumulando accumulator el valor accumulator + currentValue

En la siguiente entrega vamos a ver JavaScript — Operadores unarios

La entrega pasada vimos JavaScript — Array

--

--

No responses yet