Bucle for y for...of
Los bucles son estructuras de control que nos permiten repetir bloques de código múltiples veces. En JavaScript, tenemos diferentes tipos de bucles, cada uno diseñado para situaciones específicas.
El bucle for clásico es uno de los más utilizados cuando conocemos de antemano cuántas veces queremos repetir una acción. Su estructura es clara y predecible, lo que lo convierte en la opción ideal para contadores y iteraciones controladas.
Sintaxis del bucle for
La sintaxis del bucle for tiene tres componentes separados por punto y coma:
for (inicialización; condición; incremento) {
// Código a ejecutar
}
- Inicialización: Se ejecuta una sola vez al inicio del bucle
- Condición: Se evalúa antes de cada iteración
- Incremento: Se ejecuta después de cada iteración
Veamos un ejemplo básico que imprime números del 1 al 5:
for (let i = 1; i <= 5; i++) {
console.log(`Número: ${i}`);
}
En este ejemplo, i
es la variable de control que comienza en 1, se incrementa en cada iteración y el bucle continúa mientras i
sea menor o igual a 5.
Casos prácticos del bucle for
El bucle for es especialmente útil para realizar cálculos repetitivos o procesar secuencias numéricas:
// Calcular la suma de números del 1 al 10
let suma = 0;
for (let i = 1; i <= 10; i++) {
suma += i;
}
console.log(`La suma es: ${suma}`); // 55
También podemos crear patrones de salida interesantes:
// Crear una tabla de multiplicar del 7
for (let i = 1; i <= 10; i++) {
let resultado = 7 * i;
console.log(`7 x ${i} = ${resultado}`);
}
Bucle for...of para iterar colecciones
El bucle for...of es una adición moderna a JavaScript que simplifica la iteración sobre elementos de una colección. Su sintaxis es más limpia y legible cuando queremos procesar cada elemento sin necesidad de índices.
for (const elemento of colección) {
// Código a ejecutar con cada elemento
}
Veamos cómo funciona con diferentes tipos de datos:
Con cadenas de texto:
const palabra = "JavaScript";
for (const letra of palabra) {
console.log(letra);
}
// Imprime: J, a, v, a, S, c, r, i, p, t
Con arrays:
const colores = ["rojo", "verde", "azul"];
for (const color of colores) {
console.log(`Color: ${color}`);
}
Diferencias entre for y for...of
Es importante entender cuándo usar cada tipo de bucle. El bucle for clásico nos da control total sobre el índice y es ideal cuando necesitamos:
- Conocer la posición actual del elemento
- Iterar en orden inverso
- Saltar elementos específicos
const frutas = ["manzana", "banana", "naranja"];
// Con for clásico - acceso al índice
for (let i = 0; i < frutas.length; i++) {
console.log(`${i}: ${frutas[i]}`);
}
El bucle for...of es más simple y directo cuando solo necesitamos procesar cada elemento:
// Con for...of - más limpio y legible
for (const fruta of frutas) {
console.log(`Fruta: ${fruta}`);
}
Buenas prácticas con bucles for
Al trabajar con bucles for, es recomendable seguir ciertas convenciones de nomenclatura. Para variables de control, usa nombres descriptivos como i
, j
, k
para bucles simples, o nombres más específicos para contextos complejos:
// Para bucles simples
for (let i = 0; i < 10; i++) { }
// Para contextos específicos
for (let usuario = 0; usuario < usuarios.length; usuario++) {
console.log(`Procesando usuario ${usuario}`);
}
Cuando uses for...of, prefiere const
en lugar de let
si no vas a modificar el elemento:
// Buena práctica - usar const
for (const elemento of lista) {
console.log(elemento);
}
// Solo usar let si necesitas modificar
for (let elemento of lista) {
elemento = elemento.toUpperCase(); // Esto no modifica el array original
}
Casos de uso avanzados
Los bucles for también pueden manejar incrementos personalizados:
// Imprimir solo números pares del 2 al 20
for (let i = 2; i <= 20; i += 2) {
console.log(i);
}
// Contar hacia atrás
for (let i = 10; i >= 1; i--) {
console.log(`Cuenta atrás: ${i}`);
}
El bucle for...of también funciona con estructuras más complejas:
// Con arrays de objetos (aunque los objetos se verán más adelante)
const numeros = [1, 2, 3, 4, 5];
for (const numero of numeros) {
if (numero % 2 === 0) {
console.log(`${numero} es par`);
}
}
Bucle while y do...while
Los bucles while representan una alternativa fundamental cuando no sabemos exactamente cuántas veces necesitamos repetir una operación. A diferencia del bucle for, que es ideal para iteraciones con un número conocido de repeticiones, el while se basa en evaluar una condición antes de cada ejecución.
La principal ventaja de estos bucles radica en su flexibilidad para manejar situaciones donde la repetición depende de factores externos o condiciones que pueden cambiar durante la ejecución.
Bucle while
El bucle while evalúa una condición antes de ejecutar el bloque de código. Si la condición es verdadera, ejecuta el código; si es falsa, termina el bucle sin ejecutarlo.
while (condición) {
// Código a ejecutar mientras la condición sea verdadera
}
Un ejemplo básico muestra cómo contar hasta un límite:
let contador = 1;
while (contador <= 5) {
console.log(`Iteración: ${contador}`);
contador++; // Importante: modificar la variable para evitar bucles infinitos
}
Es crucial asegurarse de que la condición eventualmente se vuelva falsa. Sin esto, crearemos un bucle infinito que bloqueará la aplicación:
// Ejemplo de procesamiento de datos hasta cumplir una condición
let suma = 0;
let numero = 1;
while (suma < 50) {
suma += numero;
console.log(`Suma actual: ${suma}`);
numero++;
}
console.log(`Suma final: ${suma}`);
Casos prácticos del bucle while
Los bucles while son especialmente útiles para validaciones de entrada y procesamiento de datos con condiciones variables:
// Simulación de entrada de usuario válida
let edad = -1; // Valor inicial inválido
while (edad < 0 || edad > 120) {
// En un entorno real, aquí pedirías la entrada del usuario
edad = Math.floor(Math.random() * 150); // Simulamos entrada aleatoria
if (edad < 0 || edad > 120) {
console.log(`Edad ${edad} no válida, intentando de nuevo...`);
}
}
console.log(`Edad válida ingresada: ${edad}`);
También son ideales para procesar listas hasta encontrar un elemento específico:
const nombres = ["Ana", "Carlos", "María", "Juan", "Sofía"];
let indice = 0;
let encontrado = false;
while (indice < nombres.length && !encontrado) {
if (nombres[indice] === "María") {
console.log(`Encontrado ${nombres[indice]} en la posición ${indice}`);
encontrado = true;
}
indice++;
}
if (!encontrado) {
console.log("Nombre no encontrado en la lista");
}
Bucle do...while
El bucle do...while ejecuta el bloque de código al menos una vez, y después evalúa la condición. Esta diferencia es fundamental cuando necesitamos garantizar que el código se ejecute mínimo una vez.
do {
// Código que se ejecuta al menos una vez
} while (condición);
La estructura garantiza que el código dentro del do
se ejecute antes de verificar la condición:
let respuesta;
do {
// Simulamos una pregunta al usuario
respuesta = Math.random() > 0.7 ? "si" : "no";
console.log(`Respuesta: ${respuesta}`);
} while (respuesta !== "si");
console.log("¡Perfecto! Respuesta correcta recibida.");
Diferencias entre while y do...while
La diferencia clave entre ambos bucles radica en el momento de evaluación de la condición:
Bucle while - evalúa la condición antes:
let x = 10;
while (x < 5) {
console.log("Este mensaje nunca se imprimirá");
x++;
}
console.log("Bucle while terminado");
Bucle do...while - evalúa la condición después:
let y = 10;
do {
console.log("Este mensaje se imprime una vez");
y++;
} while (y < 5);
console.log("Bucle do...while terminado");
Esta diferencia los hace apropiados para contextos específicos. Usa while cuando la condición debe verificarse antes de cualquier ejecución, y do...while cuando necesitas garantizar al menos una ejecución.
Aplicaciones prácticas
Los bucles while son excelentes para algoritmos de búsqueda:
// Búsqueda de un número específico en un rango
const numeroObjetivo = 42;
let numeroActual = 1;
let intentos = 0;
while (numeroActual !== numeroObjetivo) {
numeroActual = Math.floor(Math.random() * 100) + 1;
intentos++;
console.log(`Intento ${intentos}: ${numeroActual}`);
}
console.log(`¡Encontrado ${numeroObjetivo} en ${intentos} intentos!`);
Los bucles do...while son perfectos para menús interactivos:
let opcion;
do {
console.log("=== MENÚ PRINCIPAL ===");
console.log("1. Opción A");
console.log("2. Opción B");
console.log("3. Salir");
// Simulamos selección de usuario
opcion = Math.floor(Math.random() * 4) + 1;
console.log(`Opción seleccionada: ${opcion}`);
if (opcion === 1) {
console.log("Ejecutando Opción A...");
} else if (opcion === 2) {
console.log("Ejecutando Opción B...");
} else if (opcion === 3) {
console.log("Saliendo del programa...");
} else {
console.log("Opción no válida, intenta de nuevo");
}
} while (opcion !== 3);
Consideraciones importantes
Al trabajar con bucles while, siempre ten presente la modificación de la condición. El código dentro del bucle debe eventualmente hacer que la condición se vuelva falsa:
// Correcto: la variable se modifica en cada iteración
let numero = 1;
while (numero <= 3) {
console.log(`Número: ${numero}`);
numero++; // Esta línea es crucial
}
// Peligroso: bucle infinito si no se modifica la condición
// let numero = 1;
// while (numero <= 3) {
// console.log(`Número: ${numero}`);
// // Sin incrementar numero, el bucle nunca termina
// }
También es recomendable incluir mecanismos de seguridad en bucles que podrían ejecutarse indefinidamente:
let intentos = 0;
const maxIntentos = 100;
let condicion = true;
while (condicion && intentos < maxIntentos) {
// Procesamiento aquí
intentos++;
// Lógica para cambiar la condición
if (Math.random() > 0.95) {
condicion = false;
}
}
if (intentos >= maxIntentos) {
console.log("Se alcanzó el límite máximo de intentos");
}
Control de flujo
Dentro de los bucles, a menudo necesitamos controlar el flujo de ejecución de manera más granular. JavaScript proporciona dos palabras clave esenciales para esto: break
y continue
. Estas declaraciones nos permiten alterar el comportamiento normal de los bucles, saliendo completamente o saltando iteraciones específicas según nuestras necesidades.
El control de flujo es especialmente útil cuando trabajamos con grandes volúmenes de datos o cuando queremos optimizar el rendimiento evitando procesamiento innecesario.
La declaración break
La palabra clave break termina inmediatamente la ejecución del bucle actual y transfiere el control a la siguiente instrucción después del bucle. Es como una "salida de emergencia" que nos permite abandonar el bucle cuando se cumple una condición específica.
for (let i = 1; i <= 10; i++) {
if (i === 5) {
break; // Sale del bucle cuando i es 5
}
console.log(`Número: ${i}`);
}
console.log("Bucle terminado");
// Salida: 1, 2, 3, 4, "Bucle terminado"
Esta funcionalidad es especialmente valiosa para búsquedas donde queremos detenernos tan pronto como encontremos lo que buscamos:
const estudiantes = ["Ana", "Carlos", "María", "Juan", "Sofía"];
const estudianteBuscado = "María";
let encontrado = false;
for (let i = 0; i < estudiantes.length; i++) {
if (estudiantes[i] === estudianteBuscado) {
console.log(`${estudianteBuscado} encontrado en la posición ${i}`);
encontrado = true;
break; // No necesitamos seguir buscando
}
}
if (!encontrado) {
console.log("Estudiante no encontrado");
}
Break con bucles while
El break
funciona de manera idéntica con bucles while, proporcionando una forma de salir cuando se cumpla una condición específica:
let suma = 0;
let contador = 1;
while (true) { // Bucle infinito controlado
suma += contador;
console.log(`Suma actual: ${suma}`);
if (suma > 50) {
console.log("Límite alcanzado, saliendo del bucle");
break;
}
contador++;
}
Este patrón es útil cuando la condición de salida es más compleja que una simple comparación en la declaración del while.
La declaración continue
La palabra clave continue salta la iteración actual y pasa directamente a la siguiente. A diferencia de break
, que termina todo el bucle, continue
solo omite el resto del código en la iteración actual.
for (let i = 1; i <= 10; i++) {
if (i % 2 === 0) {
continue; // Salta los números pares
}
console.log(`Número impar: ${i}`);
}
// Salida: 1, 3, 5, 7, 9
El continue
es perfecto para filtrar elementos durante el procesamiento:
const calificaciones = [85, 42, 90, 55, 78, 35, 95, 68];
let calificacionesAprobadas = 0;
for (const calificacion of calificaciones) {
if (calificacion < 60) {
continue; // Salta las calificaciones reprobadas
}
console.log(`Calificación aprobada: ${calificacion}`);
calificacionesAprobadas++;
}
console.log(`Total de calificaciones aprobadas: ${calificacionesAprobadas}`);
Casos prácticos combinados
En situaciones reales, es común combinar ambas declaraciones para crear lógicas de control más sofisticadas:
const productos = [
{ nombre: "Laptop", precio: 800, disponible: true },
{ nombre: "Mouse", precio: 25, disponible: false },
{ nombre: "Teclado", precio: 60, disponible: true },
{ nombre: "Monitor", precio: 300, disponible: true },
{ nombre: "Impresora", precio: 150, disponible: false }
];
let presupuesto = 500;
let productosComprados = 0;
for (const producto of productos) {
// Saltar productos no disponibles
if (!producto.disponible) {
console.log(`${producto.nombre} no disponible, saltando...`);
continue;
}
// Verificar si podemos comprarlo
if (producto.precio > presupuesto) {
console.log(`Presupuesto insuficiente para ${producto.nombre}`);
if (productosComprados === 0) {
continue; // Seguir buscando productos más baratos
} else {
break; // Ya compramos algo, mejor parar aquí
}
}
// Comprar el producto
presupuesto -= producto.precio;
productosComprados++;
console.log(`Comprando ${producto.nombre} por $${producto.precio}`);
console.log(`Presupuesto restante: $${presupuesto}`);
}
console.log(`Productos comprados: ${productosComprados}`);
Control de flujo en bucles anidados
Es importante entender que break
y continue
solo afectan al bucle más interno en el que se encuentran:
for (let i = 1; i <= 3; i++) {
console.log(`Bucle externo: ${i}`);
for (let j = 1; j <= 5; j++) {
if (j === 3) {
console.log(` Saltando j = ${j}`);
continue; // Solo afecta al bucle interno
}
if (j === 4 && i === 2) {
console.log(` Saliendo del bucle interno cuando i=${i}, j=${j}`);
break; // Solo sale del bucle interno
}
console.log(` Bucle interno: ${j}`);
}
console.log(`Fin del bucle externo ${i}\n`);
}
Patrones de validación con continue
El continue
es especialmente útil para validar datos y procesar solo elementos válidos:
const edades = [25, -5, 30, 150, 40, 0, 65, 200];
console.log("Procesando edades válidas:");
for (const edad of edades) {
// Validaciones múltiples
if (edad <= 0) {
console.log(`Edad ${edad} no válida: debe ser positiva`);
continue;
}
if (edad > 120) {
console.log(`Edad ${edad} no válida: demasiado alta`);
continue;
}
// Procesar solo edades válidas
const categoria = edad < 18 ? "menor" : edad < 65 ? "adulto" : "mayor";
console.log(`Edad ${edad}: ${categoria}`);
}
Optimización con break en búsquedas
Una aplicación muy práctica del break
es optimizar búsquedas deteniéndose en cuanto encontramos lo que necesitamos:
// Buscar el primer número divisible por 7 en un rango
const inicio = 100;
const fin = 200;
let encontrado = false;
for (let numero = inicio; numero <= fin; numero++) {
if (numero % 7 === 0) {
console.log(`Primer número divisible por 7 encontrado: ${numero}`);
encontrado = true;
break; // No necesitamos seguir buscando
}
}
if (!encontrado) {
console.log(`No se encontraron números divisibles por 7 entre ${inicio} y ${fin}`);
}
Consideraciones de rendimiento
El uso inteligente de break
y continue
puede mejorar significativamente el rendimiento de nuestros programas:
// Procesar solo los primeros 3 elementos válidos
const datos = [1, -2, 3, -4, 5, 6, 7, 8, 9, 10];
let elementosValidos = 0;
const limite = 3;
for (const numero of datos) {
// Saltar números negativos
if (numero < 0) {
console.log(`Saltando número negativo: ${numero}`);
continue;
}
// Procesar número válido
console.log(`Procesando número válido: ${numero}`);
elementosValidos++;
// Salir cuando hayamos procesado suficientes
if (elementosValidos >= limite) {
console.log(`Límite de ${limite} elementos alcanzado`);
break;
}
}
Buenas prácticas
Al usar estas declaraciones de control, mantén el código legible y comprensible:
- 1. Usa comentarios para explicar por qué usas break o continue:
for (let i = 0; i < datos.length; i++) {
if (datos[i] === null) {
continue; // Saltar elementos nulos para evitar errores
}
if (datos[i] > limite) {
break; // Detenerse al encontrar el primer valor fuera de rango
}
procesarDato(datos[i]);
}
- 2. Evita lógicas demasiado complejas dentro de las condiciones. Si necesitas muchas validaciones, considera extraerlas a funciones separadas:
function esValido(elemento) {
return elemento !== null && elemento > 0 && elemento < 1000;
}
function debeDetener(elemento, contador) {
return elemento > 500 || contador >= 10;
}
for (const elemento of elementos) {
if (!esValido(elemento)) {
continue;
}
if (debeDetener(elemento, procesados)) {
break;
}
// Lógica principal aquí
}
Fuentes y referencias
Documentación oficial y recursos externos para profundizar en JavaScript
Documentación oficial de JavaScript
Alan Sastre
Ingeniero de Software y formador, CEO en CertiDevs
Ingeniero de software especializado en Full Stack y en Inteligencia Artificial. Como CEO de CertiDevs, JavaScript es una de sus áreas de expertise. Con más de 15 años programando, 6K seguidores en LinkedIn y experiencia como formador, Alan se dedica a crear contenido educativo de calidad para desarrolladores de todos los niveles.
Más tutoriales de JavaScript
Explora más contenido relacionado con JavaScript y continúa aprendiendo con nuestros tutoriales gratuitos.
Aprendizajes de esta lección
- Comprender la estructura y uso del bucle for clásico para iteraciones controladas.
- Aprender a utilizar el bucle for...of para iterar colecciones de forma sencilla y legible.
- Diferenciar entre bucles while y do...while y conocer sus aplicaciones prácticas.
- Aplicar las declaraciones break y continue para controlar el flujo dentro de los bucles.
- Implementar buenas prácticas y optimizaciones en el uso de bucles en JavaScript.