Bucles: Usando forEach en JavaScript

Generalmente cuando programamos siempre buscamos facilitar procesos de modo que tendemos a ir a por lo cómodo. Esto se traduce en minimizar el número de acciones sobretodo cuando debemos repetir una tarea de manera repetitiva en un bucle. Así que antes de comenzar lo mejor es hacer una breve introducción sobre los loops en JavaScript.

Un loop no es otra cosa que un bucle: una serie de instrucciones que se utilizan para repetir parte de un código. En JavaScript podemos utilizarlos para además recorrer listas, arrays, objetos, etc.

Un ejemplo sencillo es aquel en donde necesitamos repetir “Hola Mundo” como un mensaje diez veces. En lugar de copiar el código una y otra vez, lo que hacemos es usar una instrucción de bucle para que repita la impresión de nuestro saludo tantas veces como necesitemos.

Generalmente todos los lenguajes modernos cuentan entre su sintaxis para la creación de bucles de las instrucciones for y while. Veamos las formas más comunes:

bucle for

Un bucle for se compone de una variable que actúa como contador que funcionará como el inicio y finalización de la instrucción. 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.

for(let i=0; i<5; i++){
    console.log('Hola: ' + i);
}

//output: Hola: 1
//output: Hola: 2
//output: Hola: 3
//output: Hola: 4
//output: Hola: 5

Explicación:

  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

También se puede hacer el bucle a la inversa. De manera que a partir de un valor dado a una variable ésta vaya reduciendo su valor a cada iteración:

for(let i=5; i<0; i--){
    console.log('Hola: ' + i);
}

//output: Hola: 5
//output: Hola: 4
//output: Hola: 3
//output: Hola: 2
//output: Hola: 1

bucle while

El bucle while ejecuta una y otra vez una sentencia especificada mientras la condición definida se cumpla. La diferencia con el bucle for es que no necesitas declarar un contador, solo necesita de una condición.

let num = 5;
while (num <= 150) {
  console.log(num);
  num = num * 5;
}

// output 5
// output 25
// output 125

Es importante recalcar que la condición es evaluada antes de ejecutar la sentencia.

do…while

El bucle do while ejecuta una sentencia especificada mientras la condición definida se cumpla. Pero aquí es importante recalcar que, a diferencia del bucle while, 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.

let i = 0;
do {  
 i += 1;
 console.log(i);
} while (i < 5);

 

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.

const cars = ['Ferrari 250 GT Berlinetta.', 'Tesla S', 'Génesis G90', 'Porsche Boxster'];

//Con una función de devolución ES5
cars.forEach(function (element) {
  console.log(element);
});

//Función de flecha ES6
cars.forEach(element => console.log(element));

//output Ferrari 250 GT Berlinetta
//output Tesla S
//output Génesis G90
//output Porsche Boxster

 

La instrucción break en los bucles

Para ambos bucles, existen dos instrucciones que pueden resultar bastante útiles en algunas situaciones.

La instrucción break sirve para salir del bucle for si se cumple una condición.

Hasta ahora, si querías salir del bucle tenías que poner un if justo al empezar el bucle para comprobar si podemos seguir en el bucle:

for (i = 0; i < 10; i++) { 
    if (i<5) {   
        connsole.log("Contador: " + i);
    }
}

Lo malo de esto es que aunque no se pinte el contador, la variable se sigue incrementando. Si por ejemplo tenemos un bucle que se va a ejecutar 1000 veces, si nos salimos en la segunda ejecución, el bucle seguirá ejecutándose aunque no se muestre nada

Aquí es donde entra en juego la instrucción break en javascript y en general en muchos lenguajes, para optimizar los bucles y que no se ejecuten de más. Si pones un if dentro del bucle como antes y dentro la instrucción break, en cuanto se ejecute, saldrá del bucle y no se ejecutará más pase lo que pase. Por ejemplo:

for (i = 0; i < 1000; i++) {
    if (i === 3) { break; }
    connsole.log("Contador: " + i);
}

En este ejemplo, en cuanto el contador valga 3, saldrá del bucle y no ejecutará las 996 interacciones posteriores.

La instrucción continue

La instrucción continue, sirve para saltarse instrucciones específicas, es decir, si llega a esta instrucción el bucle se saltará lo que ponga a continuación y pasará a la siguiente instrucción del bucle.>

Un ejemplo de la instrucción continue sería:

for (i = 0; i < 10; i++) {
    if (i === 4) { continue; }
    connsole.log("Contador: " + i);
}

Si ejecutas el código anterior en la consola del navegador y miras el resultado, podrás observar que no pinta el contador cuando vale 4.

For vs Foreach

¿Pero quién es más rápido? ¿Qué opción es la más aconsejable? Si tenemos que comparar en términos de rendimiento ambos bucles, la cosa se pone un poco complicada. La razón de fondo es que la mayoría de los navegadores modernos incluyen métodos que detectan ambos y optimizan el resultado. Sin embargo, es posible hacernos una idea de quién es el “pistolero más rápido al oeste del río JavaScript” enumerando paso a paso los pasos que realiza cada ciclo for y foreach:

Pasos a realizar por el ciclo for:

  1. Establecer el valor inicial de la variable de control
  2. Comprobar si se debe o no salir del ciclo
  3. Ejecutar el cuerpo del ciclo
  4. Incrementar la variable de control
  5. Volver al paso 2

Mientras forEach:

  1. Instanciar la función de llamada del ciclo
  2. Comprobar si hay un siguiente elemento a procesar
  3. Llamar a la función nuevamente para el siguiente elemento a procesar, con un nuevo contexto de ejecución (esto comprende el “alcance” de la función; por lo tanto, su contexto, argumentos, variables internas y referencias a cualquier variable externa — si se utilizan).
  4. Ejecutar el contenido de la función
  5. Finalización de la llamada a la función
  6. Volver al paso 2

Podemos deducir que un bucle for es mucho más rápido en tiempo de ejecución que un bucle forEach. Pero hay que tener en cuenta que un bucle forEach imprime sólo aquellas posiciones de un array que contengan información omitiendo posiciones vacías. Esto hace que un array complejo forEach se muestre más eficaz a la hora de manejar nuestro código a cambio de sacrificar rendimiento.

En términos prácticos, si comparamos el for con el forEach, podemos ver además que es más cómodo y limpio usar el forEach, ya que sólo invocamos el método foreach t 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.

Ventajas y desventajas de usar foreach

Cuando sacaron ES6 incluyeron una nueva forma de recorrer los elementos de un array, el bucle foreach propiamente dicho:

myArray.forEach(function (value) {
  console.log(value);
});

Pero este bucle también añadió nuevos inconvenientes.

Con este bucle no puedes hacer break ni continue. Además utilizar return dentro del bucle no evitará que se siga recorriendo hasta el final (en java por ejemplo no es así).

Este bucle se suele usar en favor del bucle for cuando necesitamos encapsular código ya que pasamos una función como parámetro al bucle foreach. Esta función se puede sustituir por una arrow function:

myArray.forEach((value) => {
  console.log(value);
});

Por cierto, si quieres usar un contador dentro del foreach lo puedes hacer así:

myArray.forEach((value, i) => {
  console.log(value);
});

La variable i se incrementará automáticamente en cada iteracción del bucle.

La ventaja de este tipo de bucles es que el código es mucho más mantenible ya que no tienes que declarar contadores todo el rato, sobre todo si es para recorrer arrays y listas.

Otro de los problemas de usar forEach es que no está garantizado el orden numérico a la hora de recorrer el array, sobre todo en versiones más antiguas de los navegadores.

El último de los problemas de este bucle es que primero se recorre todas las propiedades del array para sacar sus propiedades, por lo que el bucle será más lento que un bucle for normal, sobre todo si tiene muchos elementos.

Conclusiones

Y hasta aquí el artículo de hoy. Si ya has trabajado con JavaScript posiblemente ya conocías mucho de lo aquí descrito pero al menos espero que sirva para poner en claro los tipos de bucles más comunes y en especial los usos, ventajas y desventajas que ofrece forEach para nuestros proyectos.