Bucles
En resumen: Un bucle repite un trozo de código mientras una condición es verdadera: for cuenta desde un inicio hasta un final, while repite sin saber cuántas veces y break detiene el bucle.
Problema
¿Cuánto vas a ahorrar?
Decides ahorrar: el primer mes apartas 10 €, el segundo 20 €, el tercero 30 € y así, cada vez 10 € más. ¿Cuánto tendrás después de 4 meses?
let total = 0;total += 1 * 10;total += 2 * 10;total += 3 * 10;total += 4 * 10;console.log(total);100Funciona. Pero en 3 años serían 36 líneas, casi iguales. Y si el número de meses se escribe con el teclado, no tienes ni idea de cuántas líneas escribir. Necesitas una forma de decir «repite esto tantas veces».
La idea
for: repite mientras la condición sea verdadera
Un trozo de código que se repite se llama bucle. El que más vas a usar es for. Aquí están los números del 1 al 10:
for (let i = 1; i <= 10; i++) { console.log(i);}12345678910Los paréntesis tienen tres partes, separadas por ;:
- Inicio:
let i = 1. Se ejecuta una vez, antes que todo lo demás. Aquí se crea el contador. - Condición:
i <= 10. Se comprueba antes de cada vuelta. Si es verdadera, se ejecuta el cuerpo. Si no, el bucle termina. - Paso:
i++. Se ejecuta después de cada vuelta.
Cada ejecución del cuerpo se llama iteración, o vuelta.
Más precisamente, para curiosos
- El paso puede ser el que necesites:
i += 2(un número sí y otro no),i--(hacia atrás). - El contador
iexiste solo dentro del bucle. Después de la}de cierre ya no está, y si lo usas, el programa se detiene con ReferenceError: i is not defined. - Verás a menudo contar desde 0:
for (let i = 0; i < 10; i++). Siguen siendo 10 vueltas. Por qué se cuenta desde 0 quedará claro en la lección sobre arrays.
Míralo
Vuelta a vuelta
Este es el ahorro de la primera tarjeta, con un bucle. Fíjate en cómo cambian month y total.
let total = 0;for (let month = 1; month <= 4; month++) { total += month * 10;}console.log(total); // 100Paso a paso, en palabras
- total empieza en 0.
- month = 1. Comprobación: 1 <= 4 es verdadero, así que entramos en el cuerpo.
- Vuelta 1: total += 1 * 10, total pasa a ser 10.
- month++ hace que month sea 2. 2 <= 4: una vuelta más, total pasa a ser 30.
- month 3: total pasa a ser 60.
- month 4: total pasa a ser 100.
- month++ hace que month sea 5. 5 <= 4 es falso: el bucle termina.
- Después del bucle, total es 100.
El cuerpo es una línea y se escribe una sola vez. Para 36 meses solo cambias 4 por 36. Incluso puedes poner ahí una variable leída del teclado.
Pruébalo
Cuenta atrás
¿Qué imprimirá el programa?
for (let sec = 3; sec > 0; sec--) { console.log(sec);}console.log("¡Ya!");sec-- baja el contador después de cada vuelta. Cuando sec llega a 0, la condición sec > 0 es falsa y el bucle se detiene sin imprimir el 0. La línea después del bucle se ejecuta al final, una vez.La idea
while: hasta que llegue el final
A veces no sabes de antemano cuántas vueltas habrá. La caja registradora lee precios hasta que el cajero introduce 0, y entonces da el total. Aquí for no encaja. while sí: solo una condición, sin inicio ni paso.
let total = 0;let price = Number(await ask(""));while (price !== 0) { total += price; price = Number(await ask(""));}console.log(`Total: ${total} €`);rl.close();12470Total: 23 €Encima del código están las líneas para ask() de la lección «Entrada y salida». Aquí no se muestran, pero las necesitas, y rl.close() va al final.
El primer precio se lee antes del bucle, para que la condición tenga algo que comprobar. El siguiente se lee al final del cuerpo. Si el primer número es 0, el cuerpo no se ejecuta ni una vez.
Si quieres que el cuerpo se ejecute al menos una vez, existe do-while. La condición está abajo y se comprueba después de la vuelta. Viene bien para una pregunta que se repite hasta que la respuesta es aceptable:
let count;do { console.log("¿Cuántas entradas (de 1 a 10)?"); count = Number(await ask(""));} while (count < 1 || count > 10);console.log(`Entradas reservadas: ${count}`);rl.close();0153¿Cuántas entradas (de 1 a 10)?¿Cuántas entradas (de 1 a 10)?¿Cuántas entradas (de 1 a 10)?Entradas reservadas: 3Más precisamente, para curiosos
- Si la condición nunca se vuelve falsa, el bucle nunca termina. Es un bucle infinito: el programa se «cuelga» y tienes que detenerlo a mano. La causa más común es olvidar cambiar la variable de la condición, por ejemplo que falte
price = …al final del cuerpo. -
Después del
while (…)de un do-while se escribe un;. Si falta, JavaScript lo añade por su cuenta, pero con él el código se lee como en Java y C#. - Cualquier for se puede escribir como un while, y al revés. Eliges el que se lee con más claridad:
forpara un número conocido de vueltas,whilepara «hasta que pase algo».
Pruébalo
Encuentra el error
El programa debería sumar los números del 1 al 5: 1 + 2 + 3 + 4 + 5 = 15. Imprime 10. ¿Qué línea tiene el error?
Elige la línea con el error.
Con i < n el bucle se detiene antes de que i llegue a 5, y el 5 no se suma: 1 + 2 + 3 + 4 = 10. Hace falta i <= n.
Un error así, con una vuelta de más o de menos, es el más común con los bucles. Una «prueba en seco» lo atrapa: apunta en papel i y sum en cada vuelta.
La idea
break y continue
Dos palabras cambian el recorrido normal de un bucle.
continue salta el resto de la vuelta actual y pasa a la siguiente. Estás listando las horas de citas de 9 a 17, pero a las 13 es la pausa para comer:
for (let hour = 9; hour <= 17; hour++) { if (hour === 13) { continue; } console.log(`${hour}:00`);}9:0010:0011:0012:0014:0015:0016:0017:00break detiene todo el bucle en el acto. Buscas el primer número entre el que se divide 91. En cuanto lo encuentras, no tiene sentido seguir:
const n = 91;for (let d = 2; d < n; d++) { if (n % d === 0) { console.log(`${n} es divisible entre ${d}`); break; }}91 es divisible entre 7Más precisamente, para curiosos
breakdetiene solo el bucle en el que está. Si está en un bucle anidado (siguiente tarjeta), el exterior sigue.- Verás a menudo while (true) con un break dentro: un bucle que no termina por su condición, sino por un break en el lugar adecuado.
La idea
Un bucle dentro de otro
La sala de cine tiene 3 filas de 4 asientos. Quieres imprimir cada asiento. Para cada fila recorres todos sus asientos:
for (let row = 1; row <= 3; row++) { let line = ""; for (let seat = 1; seat <= 4; seat++) { line += `[${row}-${seat}]`; } console.log(line);}[1-1][1-2][1-3][1-4][2-1][2-2][2-3][2-4][3-1][3-2][3-3][3-4]Esto se llama bucles anidados. El bucle interior se recorre entero en cada vuelta del exterior: 3 filas · 4 asientos = 12 asientos. console.log siempre pasa a una línea nueva, así que los asientos de una fila se juntan en el texto line, y este se imprime después del bucle interior. En cada fila line empieza de nuevo, vacío.
Pruébalo
Escalera
La primera fila debe tener una estrella, la segunda dos, la cuarta cuatro. ¿Qué va en el hueco?
for (let row = 1; row <= 4; row++) {
let line = "";
for (let star = 1; star <= ; star++) {
line += "*";
}
console.log(line);
}El bucle interior tiene que dar tantas vueltas como el número de la fila. Así que su límite es row, el contador del bucle exterior.
La idea
Números aleatorios para juegos
Un juego de dados necesita un número que el programa no conoce de antemano. Te lo da Math.random():
const dice = Math.floor(Math.random() * 6) + 1;console.log(`Ha salido ${dice}`);Math.random() da un número decimal de 0 a 1, sin incluir el 1, por ejemplo 0,7316…. Multiplicado por 6, va de 0 a 6 (sin incluir el 6). Math.floor quita la parte decimal, y queda un número entero del 0 al 5. Con + 1 pasa a ser del 1 al 6.
Cada ejecución da un número distinto, así que aquí no hay salida. Y aquí tienes un bucle que tira el dado hasta que sale un seis:
let rolls = 0;let dice;do { dice = Math.floor(Math.random() * 6) + 1; rolls++;} while (dice !== 6);console.log(`Un seis después de ${rolls} tiradas`);Más precisamente, para curiosos
Math.random()no acepta un número inicial:Math.random(42)ignora el 42. Una secuencia que se repita en cada ejecución (útil para las pruebas) necesita una biblioteca aparte.
- Los números no son aleatorios de verdad: se calculan con una fórmula. Sirven para juegos, pero no para contraseñas ni seguridad.
Ejercicio
Ejercicios con bucles
Resuelve los ejercicios en tu editor. Cada uno tiene una entrada y una salida de ejemplo para comparar con la tuya. El número se lee igual que en la lección «Entrada y salida».
1. Tabla de multiplicar. Lee un número e imprime sus productos con los números del 1 al 10.
77 x 1 = 77 x 2 = 147 x 3 = 217 x 4 = 287 x 5 = 357 x 6 = 427 x 7 = 497 x 8 = 567 x 9 = 637 x 10 = 702. Número primo. Un número es primo si solo se divide entre 1 y entre sí mismo: 2, 3, 5, 7, 11… Lee un número y di si es primo. Pista: prueba los divisores desde el 2 hacia arriba y detente con break en el primero.
9191 no es primoPara 11 la salida es «11 es primo».
3. Las cifras de un número. Lee un número entero positivo. Imprímelo al revés y la suma de sus cifras. Pista: n % 10 es la última cifra, y Math.trunc(n / 10) quita la última cifra. Repite hasta que el número llegue a 0.
2024Al revés: 4202Suma de las cifras: 84. Adivina el número. La computadora «piensa» un número del 1 al 100 y tú lo buscas. Después de cada intento el programa dice «Es menor.» o «Es mayor.», y al final cuántos intentos te hicieron falta. Escríbelo primero con el número secreto 37, para poder comprobarlo con el ejemplo:
502537Es menor.Es mayor.¡Acertaste en 3 intentos!Cuando funcione, cambia el 37 por un número aleatorio del 1 al 100. Ahora ni tú sabes la respuesta.
Más ejercicios
- Del 1 al N. Lee N e imprime los números del 1 al N en una línea. Para 5:
1 2 3 4 5. - Factorial. N! = 1 · 2 · 3 · … · N. Para 5: 120.
numberguarda los números enteros exactos solo hastaNumber.MAX_SAFE_INTEGER(9007199254740991), y 20! es mayor (2432902008176640000). Para números enteros grandes JavaScript tieneBigInt: un número connal final,1n, yBigInt(...)para lo que lees de la entrada. - Primos hasta N. Imprime todos los números primos hasta N. Para 20:
2 3 5 7 11 13 17 19. La comprobación del ejercicio 2 va dentro de un bucle sobre los números: bucles anidados. - Fibonacci. Cada número es la suma de los dos anteriores: 0, 1, 1, 2, 3, 5, 8… Lee N e imprime los N primeros números. Para 10:
0 1 1 2 3 5 8 13 21 34. - Cuadrado de estrellas. Lee N e imprime un cuadrado de N × N. Para 3:
* * ** * ** * *- Triángulo de estrellas. Lo mismo, pero cada fila tiene tantas estrellas como su número. Para 3:
** ** * *- Cara o cruz. Lee N, lanza una moneda N veces con un número aleatorio (0 es cara, 1 es cruz) e imprime cuántas veces salió cada una. Cuanto mayor es N, más se acercan los dos números a N / 2.
- Piedra, papel o tijera. Un jugador contra la computadora. El jugador escribe su elección, la computadora elige al azar y el programa dice quién gana. Con do-while pregunta «¿Otra partida? (sí/no)» y al final imprime el marcador.
Más precisamente, para curiosos
Con un number normal, 22! ya no sale exacto, solo aproximado:
let result = 1;for (let i = 2; i <= 22; i++) { result *= i;}console.log(result);console.log(Number.MAX_SAFE_INTEGER);1.1240007277776077e+219007199254740991Test
Ponte a prueba
Lecciones relacionadas
Sección «Lecciones relacionadas»- Se basa en: Variables y tipos · Entrada y salida · Operadores y aritmética · Condiciones
- Continúa en: Arrays · Arrays bidimensionales · Cadenas: trabajar con texto · Funciones
- Ejercicios sobre el tema: Fundamentos del lenguaje