Ir al contenido principal

Bucle for

Introducción

El bucle for es una de las estructuras de control más utilizadas en JavaScript y en la programación en general. A diferencia de los bucles while y do-while, que se centran en repetir código mientras se cumpla una condición, el bucle for está diseñado especialmente para situaciones donde conocemos de antemano el número de iteraciones o necesitamos recorrer secuencias ordenadas de elementos. Su sintaxis compacta y expresiva permite crear iteraciones controladas con precisión, lo que lo convierte en una herramienta fundamental para cualquier programador. En este artículo, exploraremos en detalle el funcionamiento del bucle for, sus componentes y los diferentes patrones de implementación.

Sintaxis y componentes del bucle for

La sintaxis básica del bucle for se compone de tres partes principales separadas por punto y coma, todas contenidas dentro de paréntesis:

for (inicialización; condición; expresión_final) {
    // Código a ejecutar en cada iteración
}

Cada uno de estos componentes tiene una función específica:

  1. Inicialización: Se ejecuta una sola vez al principio. Generalmente se utiliza para declarar e inicializar una variable de control (contador).

  2. Condición: Se evalúa antes de cada iteración. Si es verdadera (true), se ejecuta el bloque de código; si es falsa (false), el bucle termina.

  3. Expresión final: Se ejecuta al final de cada iteración, después del bloque de código. Normalmente se utiliza para modificar la variable de control.

Veamos un ejemplo básico:

for (let i = 0; i < 5; i++) {
    console.log(`Iteración número: ${i}`);
}

La salida de este código sería:

Iteración número: 0
Iteración número: 1
Iteración número: 2
Iteración número: 3
Iteración número: 4

En este ejemplo:

  • Inicialización: let i = 0 - Creamos una variable i con valor inicial 0
  • Condición: i < 5 - El bucle continuará mientras i sea menor que 5
  • Expresión final: i++ - Incrementamos i en 1 después de cada iteración

El flujo de ejecución es el siguiente:

  1. Se ejecuta la inicialización (let i = 0)
  2. Se evalúa la condición (i < 5). Como es verdadera, se ejecuta el bloque de código.
  3. Después de ejecutar el bloque, se ejecuta la expresión final (i++)
  4. Se vuelve a evaluar la condición, y el proceso se repite hasta que la condición sea falsa.

Inicialización, condición y expresión final

Vamos a analizar cada componente con más detalle:

Inicialización

La inicialización se ejecuta una única vez al comienzo del bucle. Aunque normalmente se usa para declarar e inicializar una variable contadora, puede tener diferentes formas:

// Variable declarada e inicializada en el bucle
for (let i = 0; i < 5; i++) {
    console.log(i);
}

// Variable declarada fuera del bucle
let j;
for (j = 0; j < 5; j++) {
    console.log(j);
}

// Múltiples variables inicializadas
for (let i = 0, j = 10; i < 5; i++, j--) {
    console.log(`i = ${i}, j = ${j}`);
}

// Sin inicialización (usando punto y coma)
let k = 0;
for (; k < 5; k++) {
    console.log(k);
}

Condición

La condición se evalúa antes de cada iteración:

// Condición simple
for (let i = 0; i < 5; i++) {
    console.log(i);
}

// Condición más compleja
for (let i = 0; i * i < 25; i++) {
    console.log(i); // Muestra 0, 1, 2, 3, 4
}

// Sin condición (bucle infinito si no hay break)
for (let i = 0; ; i++) {
    console.log(i);
    if (i >= 5) break; // Necesario para evitar bucle infinito
}

Expresión final

La expresión final se ejecuta después de cada iteración:

// Incremento simple
for (let i = 0; i < 5; i++) {
    console.log(i);
}

// Decremento
for (let i = 5; i > 0; i--) {
    console.log(i); // Cuenta regresiva: 5, 4, 3, 2, 1
}

// Incremento diferente
for (let i = 0; i < 10; i += 2) {
    console.log(i); // Muestra números pares: 0, 2, 4, 6, 8
}

// Múltiples operaciones
for (let i = 0, j = 5; i < 5; i++, j--) {
    console.log(`i: ${i}, j: ${j}`);
}

// Sin expresión final (actualizando dentro del bucle)
for (let i = 0; i < 5;) {
    console.log(i);
    i++; // Incremento dentro del bloque
}

Variantes de implementación

El bucle for es muy flexible y puede implementarse de diversas formas para adaptarse a diferentes necesidades:

Bucle for sin alguno de sus componentes

Todos los componentes del bucle for son opcionales, aunque debemos mantener los punto y coma:

// Sin inicialización
let i = 0;
for (; i < 5; i++) {
    console.log(i);
}

// Sin condición (requiere break)
for (let i = 0; ; i++) {
    console.log(i);
    if (i >= 5) break;
}

// Sin expresión final
for (let i = 0; i < 5;) {
    console.log(i);
    i++; // Incremento dentro del bucle
}

// Solo con punto y coma (bucle infinito si no hay break)
let j = 0;
for (;;) {
    console.log(j++);
    if (j >= 5) break;
}

Bucle for con múltiples variables

Podemos inicializar y manipular múltiples variables:

// Incrementar una variable y decrementar otra
for (let i = 0, j = 10; i < 5; i++, j--) {
    console.log(`i: ${i}, j: ${j}`);
}

// Salida:
// i: 0, j: 10
// i: 1, j: 9
// i: 2, j: 8
// i: 3, j: 7
// i: 4, j: 6

Bucle for con cuerpo vacío

En algunos casos, todo el trabajo se puede hacer en los componentes del bucle:

// Sumar números del 1 al 10
let suma = 0;
for (let i = 1; i <= 10; suma += i, i++);
console.log(suma); // Muestra: 55

Nota: Este estilo no es recomendable porque puede reducir la legibilidad del código.

Iteración sobre secuencias numéricas

Una de las aplicaciones más comunes del bucle for es iterar sobre secuencias numéricas:

Iteración ascendente

// Números del 1 al 5
for (let i = 1; i <= 5; i++) {
    console.log(i);
}
// Muestra: 1, 2, 3, 4, 5

Iteración descendente

// Cuenta regresiva de 5 a 1
for (let i = 5; i >= 1; i--) {
    console.log(i);
}
// Muestra: 5, 4, 3, 2, 1

Saltos en la iteración

// Números pares del 0 al 10
for (let i = 0; i <= 10; i += 2) {
    console.log(i);
}
// Muestra: 0, 2, 4, 6, 8, 10

// Múltiplos de 5 hasta 50
for (let i = 5; i <= 50; i += 5) {
    console.log(i);
}
// Muestra: 5, 10, 15, 20, 25, 30, 35, 40, 45, 50

Control de flujo dentro del bucle

Dentro de un bucle for, podemos utilizar las sentencias break y continue para controlar el flujo de ejecución:

break

La sentencia break termina la ejecución del bucle completo:

// Salir del bucle cuando se encuentra un número divisible por 7
for (let i = 1; i <= 20; i++) {
    if (i % 7 === 0) {
        console.log(`¡Encontrado! ${i} es divisible por 7`);
        break; // Sale del bucle inmediatamente
    }
    console.log(`Verificando número ${i}`);
}

continue

La sentencia continue salta a la siguiente iteración, omitiendo el resto del código para la iteración actual:

// Mostrar solo números impares
for (let i = 1; i <= 10; i++) {
    if (i % 2 === 0) {
        continue; // Salta a la siguiente iteración si es par
    }
    console.log(`Número impar: ${i}`);
}
// Muestra: 1, 3, 5, 7, 9

Comparación con otros bucles

Cada tipo de bucle en JavaScript tiene sus propias características que lo hacen más adecuado para ciertas situaciones:

for vs while

// Usando for
for (let i = 0; i < 5; i++) {
    console.log(i);
}

// Equivalente usando while
let i = 0;
while (i < 5) {
    console.log(i);
    i++;
}

El bucle for es generalmente más apropiado cuando:

  • Conocemos el número exacto de iteraciones
  • Necesitamos una variable de control con un valor inicial y un paso de incremento/decremento definido
  • Queremos mantener la lógica de iteración en una sola línea

El bucle while es más adecuado cuando:

  • No sabemos cuántas iteraciones necesitaremos
  • La condición de salida depende de factores que pueden cambiar dentro del bucle
  • La lógica para continuar o terminar el bucle es más compleja

for vs for...of

JavaScript también ofrece el bucle for...of para iterar sobre elementos de colecciones:

const numeros = [10, 20, 30, 40, 50];

// Usando for con índices
for (let i = 0; i < numeros.length; i++) {
    console.log(numeros[i]);
}

// Usando for...of
for (const numero of numeros) {
    console.log(numero);
}

El bucle for tradicional es mejor cuando:

  • Necesitas el índice del elemento
  • Quieres modificar los elementos del array
  • Necesitas un control preciso sobre las iteraciones (saltar elementos, recorrer en orden inverso, etc.)

El bucle for...of es mejor cuando:

  • Solo necesitas acceder a los valores, no a sus índices
  • Quieres un código más limpio y legible
  • Trabajas con estructuras iterables (arrays, strings, maps, sets, etc.)

Patrones comunes y buenas prácticas

Iteración sobre arrays

const frutas = ["manzana", "naranja", "plátano", "fresa", "kiwi"];

// Recorrer todos los elementos
for (let i = 0; i < frutas.length; i++) {
    console.log(`Fruta ${i+1}: ${frutas[i]}`);
}

// Recorrer en orden inverso
for (let i = frutas.length - 1; i >= 0; i--) {
    console.log(`Fruta (orden inverso) ${frutas.length - i}: ${frutas[i]}`);
}

Generación de patrones

// Generar un triángulo de asteriscos
let triangulo = "";
const altura = 5;

for (let i = 1; i <= altura; i++) {
    let linea = "";
    for (let j = 1; j <= i; j++) {
        linea += "* ";
    }
    triangulo += linea + "\n";
}

console.log(triangulo);
/*
* 
* * 
* * * 
* * * * 
* * * * * 
*/

Procesamiento de datos

const temperaturas = [22, 19, 25, 30, 28, 24, 27];
let suma = 0;
let maxima = temperaturas[0];
let minima = temperaturas[0];

for (let i = 0; i < temperaturas.length; i++) {
    const temp = temperaturas[i];
    suma += temp;
    
    if (temp > maxima) {
        maxima = temp;
    }
    
    if (temp < minima) {
        minima = temp;
    }
}

const media = suma / temperaturas.length;

console.log(`Temperatura media: ${media.toFixed(1)}°C`);
console.log(`Temperatura máxima: ${maxima}°C`);
console.log(`Temperatura mínima: ${minima}°C`);

Optimización del bucle

const elementos = ["a", "b", "c", "d", "e"];

// Menos eficiente (recalcula length en cada iteración)
for (let i = 0; i < elementos.length; i++) {
    console.log(elementos[i]);
}

// Más eficiente (calcula length una sola vez)
for (let i = 0, len = elementos.length; i < len; i++) {
    console.log(elementos[i]);
}

Bucles for anidados

// Tabla de multiplicar
for (let i = 1; i <= 5; i++) {
    for (let j = 1; j <= 5; j++) {
        console.log(`${i} x ${j} = ${i * j}`);
    }
    console.log("-----------");
}

Ejemplos prácticos

Ejemplo 1: Cálculo de factorial

function calcularFactorial(n) {
    if (n < 0) return "No existe el factorial de números negativos";
    
    let factorial = 1;
    
    // Usando bucle for
    for (let i = 2; i <= n; i++) {
        factorial *= i;
    }
    
    return factorial;
}

console.log(calcularFactorial(5)); // Muestra: 120

Ejemplo 2: Generar secuencia Fibonacci

function generarFibonacci(n) {
    if (n <= 0) return [];
    if (n === 1) return [0];
    
    const secuencia = [0, 1];
    
    for (let i = 2; i < n; i++) {
        const siguienteNumero = secuencia[i - 1] + secuencia[i - 2];
        secuencia.push(siguienteNumero);
    }
    
    return secuencia;
}

console.log(generarFibonacci(10)); 
// Muestra: [0, 1, 1, 2, 3, 5, 8, 13, 21, 34]

Ejemplo 3: Verificar si un número es primo

function esPrimo(numero) {
    if (numero <= 1) return false;
    if (numero <= 3) return true;
    if (numero % 2 === 0 || numero % 3 === 0) return false;
    
    // Comprobamos divisores desde 5 hasta la raíz cuadrada del número
    for (let i = 5; i * i <= numero; i += 6) {
        if (numero % i === 0 || numero % (i + 2) === 0) {
            return false;
        }
    }
    
    return true;
}

// Mostrar números primos del 1 al 50
for (let i = 1; i <= 50; i++) {
    if (esPrimo(i)) {
        console.log(`${i} es un número primo`);
    }
}

Ejemplo 4: Filtrado de elementos de un array

function filtrarNumerosPares(numeros) {
    const pares = [];
    
    for (let i = 0; i < numeros.length; i++) {
        if (numeros[i] % 2 === 0) {
            pares.push(numeros[i]);
        }
    }
    
    return pares;
}

const listaNumeros = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
console.log(filtrarNumerosPares(listaNumeros)); 
// Muestra: [2, 4, 6, 8, 10]

Ejemplo 5: Buscar el índice de un elemento

function buscarIndice(array, elemento) {
    for (let i = 0; i < array.length; i++) {
        if (array[i] === elemento) {
            return i;
        }
    }
    
    return -1; // No encontrado
}

const frutas = ["manzana", "naranja", "plátano", "fresa"];
console.log(buscarIndice(frutas, "plátano")); // Muestra: 2
console.log(buscarIndice(frutas, "kiwi"));    // Muestra: -1

Resumen

El bucle for es una estructura de control versátil y potente en JavaScript que nos permite ejecutar código repetidamente con un control preciso sobre el número de iteraciones. Su estructura organizada en tres componentes (inicialización, condición y expresión final) lo hace especialmente adecuado para casos donde conocemos de antemano el número de repeticiones o necesitamos iterar sobre secuencias de elementos.

Hemos visto cómo funciona la sintaxis básica del bucle for, sus diversas variantes y cómo podemos controlar su flujo mediante sentencias como break y continue. También hemos analizado las diferencias con otros tipos de bucles y cuándo es más apropiado usar cada uno.

Entre las aplicaciones más comunes del bucle for se encuentran la iteración sobre arrays, la generación de patrones, el procesamiento de datos y la implementación de algoritmos. Su flexibilidad y expresividad lo convierten en una herramienta esencial en el arsenal de cualquier programador de JavaScript.

Aunque existen alternativas más modernas como forEach, map, filter y otros métodos de array para ciertos casos específicos, el bucle for clásico sigue siendo fundamental por su rendimiento, su versatilidad y el control preciso que ofrece sobre las iteraciones.