Skip to content
This page has been auto-translated and may contain errors.View in English

Bucles

docs.scrimba.com

Digamos que quieres imprimir los números del 1 al 100, o saludar cada carácter en una palabra, o seguir haciendo una pregunta hasta que la respuesta sea correcta. Podrías escribir la misma línea cien veces, pero eso es tedioso de escribir y peor de cambiar. Un bucle es cómo le dices a JavaScript que ejecute un trozo de código una y otra vez, así escribes el trabajo una sola vez y dejas que el lenguaje haga la repetición. Este capítulo cubre los tres bucles que usarás más: for, while y for...of.

El bucle for

El bucle for es el que usas cuando sabes cuántas veces repetir. Cuenta por ti. Aquí está imprimiendo los números del 0 al 4:

js
for (let i = 0; i < 5; i++) {
  console.log(i);
}
// 0
// 1
// 2
// 3
// 4

La parte entre paréntesis tiene tres piezas, separadas por punto y coma:

  • let i = 0 es el inicio: crea un contador llamado i y lo establece en 0.
  • i < 5 es la condición: el bucle sigue mientras esto sea verdadero.
  • i++ es el paso: después de cada pasada, suma 1 a i (i++ es corto para i = i + 1).

Así que el bucle inicia i en 0, comprueba que i < 5, ejecuta el código entre llaves, luego suma 1 y comprueba de nuevo. Cuando i llega a 5 la condición es falsa y el bucle se detiene.

El bucle for está diseñado para el caso en el que conoces el número de repeticiones de antemano. Empaqueta tres piezas en su encabezado, ejecutadas en orden:

js
for (let i = 0; i < 5; i++) {
  console.log(`pasada número ${i}`);
}
// pasada número 0
// pasada número 1
// pasada número 2
// pasada número 3
// pasada número 4

Leyendo el encabezado de izquierda a derecha: let i = 0 es el inicializador, ejecutado una sola vez antes que nada. i < 5 es la condición, comprobada antes de cada pasada, y el bucle se ejecuta solo mientras sea verdadera. i++ es el paso, ejecutado después de cada pasada. El contador i es una variable normal, así que puedes leerlo dentro del bucle, que es por qué los bucles y el conteo van juntos.

El contador comienza en 0 por convención, no por regla. Contar desde 0 es lo que verás casi en todas partes en JavaScript, y se alinea con cómo los arrays numeran sus elementos, así que vale la pena sentirse cómodo con esto desde el principio.

El bucle for codifica toda la forma de una repetición contada en un encabezado: inicializador, condición y paso, cada uno separado por punto y coma.

js
for (let i = 0; i < 5; i++) {
  console.log(`pasada número ${i}`);
}
// pasada número 0
// pasada número 1
// pasada número 2
// pasada número 3
// pasada número 4

El orden es exacto y vale la pena internalizarlo: el inicializador se ejecuta una sola vez, luego se prueba la condición, y solo si es verdadera se ejecuta el cuerpo, seguido del paso, y luego de vuelta a la condición. Es por eso que la condición se comprueba antes de la primera pasada, así que un bucle cuya condición comience siendo falsa nunca ejecuta su cuerpo en absoluto.

Usa let para el contador, no const, porque el paso lo reasigna en cada pasada. Y declarar i en el encabezado lo sitúa dentro del bucle, así no se filtra en el código circundante, lo que evita que los contadores choquen cuando anidar bucles o escribir varios seguidos. Contar desde 0 en lugar de 1 es la convención casi universal aquí, y mapea directamente cómo los arrays indexan sus elementos, así que el hábito se paga desde el momento en que haces bucles sobre datos.

JunoEl bucle for El bucle for se repite un número fijo de veces y cuenta por ti. Su encabezado tiene tres partes: un inicio como let i = 0, una condición como i < 5 que lo mantiene funcionando, y un paso como i++ que lo mueve adelante. Cuando la condición se vuelve falsa, el bucle se detiene.
JunoEl bucle for Recurre a for cuando conoces el conteo de antemano. El encabezado ejecuta el inicializador una sola vez, comprueba la condición antes de cada pasada, y ejecuta el paso después de cada una. Contar desde 0 es la convención, y se alinea con cómo los arrays numeran sus elementos, así que adopta este hábito ahora.
JunoEl bucle for El orden del encabezado es fijo: inicializa una sola vez, prueba la condición, ejecuta el cuerpo, ejecuta el paso, repite. Es por eso que una condición que comienza siendo falsa salta el cuerpo completamente. Usa let para el contador para que el paso pueda reasignarlo, y decláralo en el encabezado para que se mantenga dentro del alcance del bucle.

El bucle while

A veces no sabes cuántas veces repetir, solo sabes una condición que debería mantenerse verdadera. Para eso es el bucle while. Sigue ejecutándose mientras su condición se mantenga:

js
let count = 3;
while (count > 0) {
  console.log(count);
  count = count - 1;
}
console.log("¡Comenzar!");
// 3
// 2
// 1
// ¡Comenzar!

El bucle comprueba count > 0, ejecuta el código, luego comprueba de nuevo. Observa que algo dentro del bucle cambia count, así la condición finalmente se vuelve falsa y el bucle se detiene. Si nada dentro jamás hace que la condición sea falsa, el bucle se ejecuta por siempre. Ese es un bucle infinito, y congelará tu programa, así que siempre asegúrate de que la condición pueda cambiar.

Un bucle while se repite mientras una condición permanece verdadera, y no tiene un contador o paso incorporado. Eso lo hace la herramienta correcta cuando el número de repeticiones no se conoce de antemano, y un bucle for la herramienta correcta cuando sí se conoce.

js
let attempts = 0;
let password = "";
while (password !== "permiteme") {
  password = "permiteme"; // simulación de un prompt real
  attempts = attempts + 1;
}
console.log(`Desbloqueado después de ${attempts} intento(s)`);
// Desbloqueado después de 1 intento(s)

La condición (password !== "permiteme") se apoya en los operadores de comparación de condicionales, y el bucle se ejecuta hasta que se vuelve falsa. El problema es que nada la obliga a volverse falsa: tienes que cambiar algo dentro del bucle que la condición dependa de. Un bucle while cuya condición nunca se vuelve falsa se ejecuta por siempre. Ese es un bucle infinito, y cuelga el programa.

Un bucle while es la forma general: se repite mientras una condición es verdadera y deja el conteo, si lo hay, completamente en tus manos. Recurre a él cuando el número de iteraciones no es fijo, por ejemplo repetir hasta que una entrada se valide o un valor cruce un umbral. Cuando el conteo es conocido, un bucle for expresa esa intención más claramente.

js
let remaining = 100;
let steps = 0;
while (remaining > 0) {
  remaining = remaining - 15;
  steps = steps + 1;
}
console.log(`Vaciado en ${steps} pasos`);
// Vaciado en 7 pasos

El modo de fallo a respetar es el bucle infinito: while no te da garantía estructural de terminación, así que el cuerpo debe mover la condición hacia falsa. Tres cosas causan que un bucle se cuelgue: una condición que nunca se actualiza, una actualización que se mueve en la dirección incorrecta, y una condición que puede saltarse en lugar de cumplirse (usar remaining === 0 arriba lo fallaría, ya que remaining llega a un número negativo, no exactamente 0). Cada bucle while necesita una línea que empuje su condición hacia falsa. Prefiere una prueba de rango como > 0 sobre una exacta === 0 para que un paso que se exceda todavía termine el bucle.

JunoEl bucle while Un bucle while se repite mientras su condición sea verdadera, sin contador incorporado. Úsalo cuando no conozcas el número de repeticiones de antemano. Siempre cambia algo dentro del bucle para que la condición pueda volverse falsa, o obtendrás un bucle infinito que congela el programa.
JunoEl bucle while Elige while cuando el número de repeticiones es desconocido, y for cuando es fijo. El cuerpo debe cambiar lo que prueba la condición, o nunca se vuelve falsa. Ese es el bucle infinito, y es el error a vigilar cada vez que escribes un while.
JunoEl bucle whilewhile no garantiza que jamás se detenga, así que el cuerpo debe empujar la condición hacia falsa. Tres formas en que se cuelga: la condición nunca se actualiza, se mueve en la dirección incorrecta, o se salta. Prefiere una prueba de rango como > 0 sobre una exacta === 0 para que un paso que se exceda todavía termine el bucle.

Hacer bucles sobre un string con for...of

Los bucles for y while cuentan con un número, pero a menudo quieres visitar cada elemento en algo directamente. for...of hace eso. Aquí camina a través de cada carácter de una palabra:

js
for (const char of "hola") {
  console.log(char);
}
// h
// o
// l
// a

Léelo como "para cada carácter de la palabra". En cada pasada, char mantiene el siguiente carácter, y nunca tocas un contador o una condición. Es más limpio que un bucle for cuando todo lo que quieres es mirar cada elemento a su vez.

Usarás for...of principalmente en arrays, que son listas de valores que conocerás en los próximos capítulos. Un string es una buena primera cosa sobre la que hacer un bucle porque ya es una secuencia de caracteres, y for...of la trata exactamente así.

for...of itera los elementos de una secuencia directamente, poniéndote cada valor a su vez sin un contador o una condición que gestionar:

js
let vowels = 0;
for (const char of "javascript") {
  if (char === "a" || char === "i") {
    vowels = vowels + 1;
  }
}
console.log(`Encontradas ${vowels} de esas vocales`);
// Encontradas 3 de esas vocales

Usar const char aquí es deliberado: cada pasada crea un char fresco que solo lees, nunca reasignas, así que const encaja y señala esa intención. Un bucle for...of intercambia la gestión manual de un bucle contador por legibilidad, y elimina toda una clase de errores de uno por más porque nunca indexas manualmente.

Los strings son una primera secuencia natural sobre la que hacer un bucle, pero el caballo de batalla es el array. Una vez que conozcas arrays, for...of es la forma limpia y directa de caminar su contenido.

for...of itera cualquier secuencia elemento por elemento, vinculando cada valor a un nombre sin exponer un índice. En un string produce caracteres:

js
let shout = "";
for (const char of "bucles") {
  shout = shout + char.toUpperCase();
}
console.log(shout);
// BUCLES

Vincula la variable del bucle con const: for...of crea un nuevo vínculo cada pasada, así que nada necesita reasignarlo, y const documenta que el valor es de solo lectura dentro del cuerpo. La recompensa sobre un bucle contador es que nunca escribes un índice, lo que evita errores de uno por más por construcción.

Donde esto importa más es en arrays. Para visitar cada elemento, for...of se lee más limpio que un bucle for contador y expresa la intención directamente. Pero cuando estás transformando una colección en una nueva, los métodos de iteración de arrays generalmente reemplazan el bucle manual completamente, y se cubren en su propio capítulo.

break y continue

Dos palabras clave te dan control más fino dentro de cualquier bucle. break detiene el bucle inmediatamente y se mueve al código después de él. continue salta el resto de la pasada actual y salta directo a la siguiente.

js
for (let i = 0; i < 10; i++) {
  if (i === 3) {
    continue; // salta 3, sigue bucleando
  }
  if (i === 6) {
    break; // detén el bucle completamente
  }
  console.log(i);
}
// 0
// 1
// 2
// 4
// 5

break es cómo paras temprano una vez que has encontrado lo que necesitas, así no sigues escaneando sin propósito. continue es cómo saltas casos que no te importan sin anidar el resto del cuerpo dentro de un if.

Errores de uno por más e índices fuera de rango

El bug clásico de bucles es el error de uno por más: ejecutarse una vez demasiadas o una muy pocas. Viene de los límites del contador. Un string de longitud 5 tiene caracteres en las posiciones 0, 1, 2, 3 y 4, así que la última posición válida es length - 1, no length. Por eso un bucle contador sobre sus posiciones usa i < text.length, no i <= text.length:

js
const text = "hola";
for (let i = 0; i < text.length; i++) {
  console.log(text[i]);
}
// h
// o
// l
// a

Escribe i <= text.length y la última pasada alcanza la posición 5, que no existe, así que produce undefined. Contar desde 0 con < hasta la longitud es el patrón que cae exactamente en cada posición y no más. Cuando solo necesitas cada elemento y no su posición, for...of evita la pregunta de límites completamente, que es una razón para preferirlo.

JunoHacer bucles sobre un string con for...offor...of visita cada elemento directamente, sin contador y sin condición que gestionar. En un string, cada pasada te da el siguiente carácter. Lo usarás más en arrays después, pero un string es una primera cosa limpia sobre la que hacer un bucle porque ya es una secuencia de caracteres.
JunoHacer bucles sobre un string con for...offor...of te pone cada valor a su vez, así que saltas el contador y el riesgo de uno por más que viene de indexar manualmente. Vincula con const ya que cada pasada es de solo lectura. Los strings son un buen inicio, pero los arrays son donde lo usarás mucho una vez que los conozcas.
JunoHacer bucles sobre un string con for...offor...of vincula cada elemento a un const fresco y nunca expone un índice, lo que elimina bugs de uno por más por construcción. break detiene temprano, continue salta una pasada. Para transformar una colección en lugar de solo caminarla, los métodos de iteración de arrays generalmente reemplazan el bucle manual, y obtienen su propio capítulo.

A dónde van los bucles desde aquí

Los bucles son cómo dejas de repetirte a ti mismo y dejas que el lenguaje haga la repetición. El bucle for cuenta un número conocido de veces, while se repite mientras una condición se mantiene, y for...of camina los elementos de una secuencia directamente. El único hábito a llevar de aquí: asegúrate de que cada bucle pueda terminar, y prefiere for...of cuando solo necesitas cada elemento.

La verdadera razón por la que importan los bucles es que la mayoría de los datos con los que trabajas vienen en colecciones. Los próximos capítulos introducen arrays, las listas sobre las que harás bucles constantemente, y más tarde los métodos de arrays que a menudo reemplazan un bucle escrito a mano cuando estás transformando datos. Si quieres afilar las condiciones en las que tus bucles dependen, condicionales cubre las comparaciones que deciden cuándo un bucle sigue funcionando y cuándo se detiene.