Mejores prácticas para la iteración en JavaScript

Mejores prácticas para la iteración en JavaScript

Este artículo explica las mejores prácticas para la iteración en JavaScript.

YouTube Video

Mejores prácticas para la iteración en JavaScript

En JavaScript, es común usar bucles for para la iteración. Aquí, proporcionaremos una explicación detallada de las mejores prácticas para usar bucles for y escribir código eficiente y legible.

Elige la estructura de bucle adecuada

JavaScript ofrece múltiples estructuras de bucles, cada una adecuada para diferentes propósitos.

 1// Example of a for loop
 2for (let i = 0; i < 5; i++) {
 3    console.log(i);
 4}
 5
 6// Example of a for...of loop
 7const array = [10, 20, 30];
 8for (const value of array) {
 9    console.log(value);
10}
11
12// Example of a for...in loop
13const obj = { a: 1, b: 2, c: 3 };
14for (const key in obj) {
15    console.log(`${key}: ${obj[key]}`);
16}
17
18// Example of a while loop
19let count = 0;
20while (count < 5) {
21    console.log(count);
22    count++;
23}
  • La declaración for es adecuada cuando el número de iteraciones está predeterminado.
  • La declaración for...of es adecuada para procesar de manera concisa arrays y objetos iterables.
  • La declaración for...in se utiliza para iterar sobre las propiedades de un objeto. Sin embargo, no es adecuado para arreglos.
  • Las declaraciones while y do...while se utilizan para controlar bucles basados en condiciones.

Uso del método forEach y la declaración for...of

Al recorrer un array, es común usar una declaración for para acceder al índice, pero el método forEach o la declaración for...of pueden ser más legibles.

 1// Using a standard for loop
 2const array = ["apple", "banana", "cherry"];
 3for (let i = 0; i < array.length; i++) {
 4    console.log(array[i]);
 5}
 6
 7// Using forEach
 8array.forEach(item => console.log(item));
 9
10// Using for...of
11for (const item of array) {
12    console.log(item);
13}
  • La declaración for permite la gestión explícita del índice durante la iteración.
  • El método forEach utiliza una función de callback para procesar cada elemento de manera concisa.
  • La declaración for...of es altamente legible y permite acceder directamente a cada elemento de un array.

Optimiza las condiciones del bucle

Dado que la condición del bucle se evalúa repetidamente, evitar cálculos innecesarios puede mejorar el rendimiento.

 1const names = ["Alice", "Bob", "Charlie"];
 2const scores = [85, 92, 78];
 3
 4// Inefficient example
 5for (let i = 0; i < Math.min(names.length, scores.length); i++) {
 6    console.log(`${names[i]} scored ${scores[i]}`);
 7}
 8
 9// Efficient example
10for (let i = 0, len = Math.min(names.length, scores.length); i < len; i++) {
11    console.log(`${names[i]} scored ${scores[i]}`);
12}
  • Como se muestra en este ejemplo, almacenar el resultado del cálculo en una variable de antemano permite una ejecución del bucle más eficiente.
 1const scores = [85, 92, 78];
 2let sum = 0;
 3let sum2 = 0;
 4
 5// Inefficient example
 6for (let i = 0; i < scores.length; i++) {
 7    sum += scores[i];
 8}
 9console.log(`Total score : ${sum}`);
10
11// Efficient example
12for (let i = scores.length - 1; i >= 0; i--) {
13    sum2 += scores[i];
14}
15console.log(`Total score : ${sum2}`);
  • Como se muestra en este ejemplo, invertir la condición puede ser más eficiente en ocasiones.

Optimizando el procesamiento de bucles

Dado que el procesamiento de bucles se ejecuta repetidamente, evitar cálculos innecesarios puede mejorar el rendimiento.

 1const array = ["apple", "banana", "cherry"];
 2
 3// Inefficient example
 4for (let i = 0; i < 100; i++) {
 5    const element = document.querySelector("#myElement");
 6    element.textContent = `Count: ${i}`;
 7}
 8
 9// Efficient example
10const element = document.querySelector("#myElement");
11for (let i = 0; i < 100; i++) {
12    element.textContent = `Count: ${i}`;
13}
  • En este ejemplo, al mover el método querySelector fuera del bucle, se eliminan cálculos repetidos innecesarios.

Sé consciente del alcance

Usa let o const para asegurar que las variables dentro del bucle tengan el alcance adecuado. Dado que var está limitado al alcance de función, puede causar comportamientos inesperados.

 1// Using let
 2for (let i = 0; i < 3; i++) {
 3    console.log(i);
 4}
 5
 6// Potential issue with var
 7for (var i = 0; i < 3; i++) {
 8    setTimeout(() => console.log(i), 1000); // 3, 3, 3
 9}
10
11// Using let to avoid the issue
12for (let i = 0; i < 3; i++) {
13    setTimeout(() => console.log(i), 1000); // 0, 1, 2
14}
  • var tiene alcance de función, por lo que después del bucle i es 3, y todas las funciones ejecutadas por setTimeout devuelven 3.
  • Usando let, la i dentro de la función de retorno (callback) de setTimeout se refiere a un nuevo valor para cada iteración del bucle, por lo que se devuelve 0, 1, 2 como se espera.

Mejora la legibilidad con salidas tempranas

Para simplificar el procesamiento del bucle, utiliza adecuadamente break y continue para mejorar la legibilidad.

 1// Example using break
 2for (let i = 0; i < 10; i++) {
 3    if (i === 5) {
 4        break; // Exit the loop
 5    }
 6    console.log(i);
 7}
 8
 9// Example using continue
10for (let i = 0; i < 10; i++) {
11    if (i % 2 === 0) {
12        continue; // Skip to the next iteration
13    }
14    console.log(i);
15}
  • Usar break te permite terminar el procesamiento del bucle a mitad de camino, saltando todas las iteraciones posteriores.
  • Usar continue te permite omitir el proceso actual del bucle y pasar a la siguiente iteración.

Evita anidaciones profundas

Las anidaciones profundas dificultan la lectura del código, por lo que se recomienda mantenerlas a un nivel mínimo mediante salidas tempranas o dividiendo la funcionalidad en funciones.

 1// Deeply nested example
 2for (let i = 0; i < 5; i++) {
 3    for (let j = 0; j < 5; j++) {
 4        if (i + j > 5) {
 5            console.log(i, j);
 6        }
 7    }
 8}
 9
10// Improved using function decomposition
11function processPairs(i) {
12    for (let j = 0; j < 5; j++) {
13        if (i + j > 5) {
14            console.log(i, j);
15        }
16    }
17}
18
19for (let i = 0; i < 5; i++) {
20    processPairs(i);
21}
  • En este ejemplo, se utilizan funciones para reducir la anidación.

Considere el manejo de errores

Si existe la posibilidad de que ocurran errores dentro del bucle, implemente un manejo de errores adecuado.

 1const data = ["123", "abc", "456", "xyz"];
 2
 3// Without Error Handling
 4for (const item of data) {
 5    const result = parseInt(item);
 6    console.log(`Parsed value: ${result}`);
 7}
 8
 9// With Error Handling
10for (const item of data) {
11    try {
12        const result = parseInt(item);
13        if (isNaN(result)) {
14            throw new Error(`Invalid number: ${item}`);
15        }
16        console.log(`Parsed value: ${result}`);
17    } catch (error) {
18        console.error(`Error processing item: ${item}. ${error.message}`);
19    }
20}
  • En este ejemplo, se realiza la gestión de errores para procesar datos no válidos, detectando y reportando problemas.

Puntos a tener en cuenta en el procesamiento asincrónico

Al manejar el procesamiento asincrónico en bucles, usar async/await puede producir un código conciso e intuitivo.

 1const urls = ["https://example.com/1", "https://example.com/2"];
 2
 3// Proper handling of asynchronous operations
 4async function fetchUrls() {
 5    for (const url of urls) {
 6        const response = await fetch(url);
 7        const data = await response.json();
 8        console.log(data);
 9    }
10}
11
12fetchUrls();
  • Este código obtiene asincrónicamente URLs del array urls una por una y procesa los resultados en formato JSON. Usar async/await simplifica las operaciones asíncronas, obteniendo datos de manera secuencial para cada URL y mostrándolos en la consola.

Entienda la diferencia entre la declaración for...of y forEach() en el procesamiento asincrónico.

 1async function asyncTask(num) {
 2    return new Promise(resolve => {
 3        setTimeout(() => {
 4            console.log(`Task ${num} done`);
 5            resolve();
 6        }, 100);
 7    });
 8}
 9
10async function runWithForOf() {
11    console.log("Start for...of");
12    for (const num of [1, 2, 3]) {
13        await asyncTask(num);
14    }
15    console.log("End for...of");
16}
17
18async function runWithForEach() {
19    console.log("Start forEach");
20    [1, 2, 3].forEach(async num => {
21        await asyncTask(num);
22    });
23    console.log("End forEach");
24}
25
26async function executeExamples() {
27    await runWithForOf();
28    await runWithForEach();
29}
30
31executeExamples();
  • Al manejar el procesamiento asincrónico en bucles, tome en cuenta las diferencias en el comportamiento, como se muestra en este ejemplo, entre usar for...of con async/await y usar forEach().

  • Con for...of, el código se ejecuta secuencialmente y espera en el await dentro del bucle antes de continuar con la siguiente iteración. Por otro lado, forEach() ejecuta el procesamiento en paralelo.

Conclusión

La declaración for en JavaScript es una herramienta simple pero poderosa. Al aprovechar las mejores prácticas presentadas aquí, puede escribir un código eficiente y altamente legible. Preste atención a seleccionar estructuras de bucle apropiadas, gestión de alcance, manejo de errores y apunte a un código altamente mantenible.

Puedes seguir el artículo anterior utilizando Visual Studio Code en nuestro canal de YouTube. Por favor, también revisa nuestro canal de YouTube.

YouTube Video