Aprende leyendo en orden

Bucles — for, for...of y for...in

Aprende los bucles de JavaScript desde cero: for para contar, for...of para recorrer elementos, for...in para las claves y cómo armar bucles anidados.

Para imprimir el precio de cada producto de un pedido en su propia línea, tendrías que escribir la misma línea 3 veces si hay 3 productos y 10 veces si hay 10. La cantidad de productos depende de los datos, así que no puedes saber de antemano cuántas líneas vas a necesitar.

En este artículo verás for, que repite contando; for...of, que te entrega los elementos uno por uno, y for...in, que recorre claves.

Repetir el mismo código por cada elemento — las tres expresiones de for

Supón que quieres imprimir los nombres de los productos de un pedido, uno por línea. Si los escribes uno a uno, empezando por console.log(orderLines[0]), tendrás que añadir una línea en cuanto el pedido llegue a 4 productos, y modificar el código cada vez que cambie la cantidad.

Un bucle for (una sentencia que repite el mismo código llevando la cuenta de las vueltas) lleva entre paréntesis tres expresiones separadas por punto y coma, y el código que quieres repetir va entre llaves. Lo que hay dentro de esas llaves se llama cuerpo. De izquierda a derecha, las tres expresiones son la inicialización, la condición y la actualización: la condición se comprueba antes de entrar al cuerpo y la actualización se ejecuta después del cuerpo.

i++ significa lo mismo que i = i + 1. Como su valor cambia en cada vuelta, i se declara con let.

const orderLines = ["Taza", "Cuaderno", "Bolígrafo"];   // nombres de los productos del pedido

// i empieza en 0 y aumenta de 1 en 1 con i++ hasta llegar a la cantidad de productos
for (let i = 0; i < orderLines.length; i++) {
  // Los índices empiezan en 0, así que se muestra i + 1 para contar desde 1
  console.log(`Producto ${i + 1}: ${orderLines[i]}`);
}
// Producto 1: Taza
// Producto 2: Cuaderno
// Producto 3: Bolígrafo

console.log(`Productos mostrados: ${orderLines.length}`);   // Productos mostrados: 3
Una vuelta de un bucle for
Inicializaciónlet i = 0Condicióni < 3Cuerpomuestra1 productoActualizacióni++Fin del buclese cumplede nuevono se cumple

La inicialización se ejecuta una sola vez, al principio; la condición, antes del cuerpo, y la actualización, después del cuerpo. En la vuelta en que la condición deja de cumplirse, el bucle termina sin ejecutar el cuerpo.

Comprobar la condición, ejecutar el cuerpo y ejecutar la actualización forman juntos una vuelta (una iteración). Como la actualización se ejecuta después del cuerpo, i siempre coincide con el número de veces que el cuerpo ya terminó, así que en la primera vuelta el cuerpo se ejecuta con i todavía en 0.

La tabla muestra el valor de i y la comprobación de la condición en cada vuelta.

VueltaValor de i y condiciónQué pasa en el cuerpo
Vuelta 1i = 0 / 0 < 3 se cumpleProducto 1: Taza
Vuelta 2i = 1 / 1 < 3 se cumpleProducto 2: Cuaderno
Vuelta 3i = 2 / 2 < 3 se cumpleProducto 3: Bolígrafo
Inicio de la vuelta 4i = 3 / 3 < 3 no se cumpleEl cuerpo no se ejecuta y el bucle termina

Leer más allá del final de un array da undefined

Si escribes la condición como i <= orderLines.length, el bucle da una vuelta de más al final y lee orderLines[3], un elemento que no existe. Cualquier posición fuera de rango devuelve undefined, así que verás "Producto 4: undefined", y si el bucle está sumando precios, el resultado se convierte en NaN. Haz que el bucle continúe solo mientras el índice sea menor que la cantidad de elementos.

Suma los precios de los productos de un carrito. El array de precios unitPrices ya está declarado.

① Prepara una variable para el total que empiece en 0.

② Usa for para contar desde 0 y suma cada precio al total.

③ Imprime el total con la forma "Total: ◯◯ yenes".

④ Divide entre la cantidad de productos para obtener el promedio, redondea hacia abajo e imprímelo con la forma "Promedio: ◯◯ yenes".

(Si se ejecuta correctamente, aparecerá una explicación.)

Editor JavaScript / TypeScript

Ejecutar el código para ver el resultado

Obtener cada elemento directamente — for...of y entries

Supón que quieres procesar, uno tras otro, los números de pedido pendientes de envío. Con for tendrías que declarar una variable de índice, escribir la condición y la actualización, y luego leer cada uno con orderIds[i]; y si te equivocas al escribir el índice, lees el elemento equivocado.

for...of (una sentencia que toma uno a uno los elementos de un array u otro iterable y guarda cada uno en una variable) se escribe for (const orderId of orderIds), con solo la declaración y el array entre los paréntesis.

Cuando también necesitas la posición, recorre orderIds.entries(). En cada vuelta te da un par como [0, "A-1001"], que desestructuras con corchetes como [index, orderId].

const orderIds = ["A-1001", "A-1002", "A-1003"];   // números de pedido pendientes de envío

// orderId contiene el propio elemento (el índice no aparece)
for (const orderId of orderIds) {
  console.log(`Pendiente de envío: ${orderId}`);
}
// Pendiente de envío: A-1001 … (3 líneas)

// Si también necesitas el índice, obtén pares con entries()
for (const [index, orderId] of orderIds.entries()) {
  console.log(`#${index + 1}: ${orderId}`);
}
// #1: A-1001
// #2: A-1002
// #3: A-1003
Cómo lo obtienesQué contiene la variableLínea impresa
Elementos con ofEl propio elemento (A-1001)Pendiente de envío: A-1001
entries() en [index, orderId]index: 0 / orderId: A-1001#1: A-1001
entries() en una sola variableEl par de índice y elementoEl array [0, "A-1001"] tal cual

const [index, orderId] funciona igual que la desestructuración de arrays del artículo sobre desestructuración: el índice va en la primera posición y el elemento en la segunda. En cada vuelta se crea una variable nueva, así que puedes declarar la variable de un bucle for...of con const sin que salte un error de reasignación.

Busca los pedidos que todavía no llegaron en una lista de estados de entrega. El array deliveries ya está declarado; cada pedido tiene un número de pedido (id) y un estado (status).

① Usa for...of para obtener los pedidos uno a uno e imprime cada uno con la forma "A-1001: Entregado".

② Recorre la lista otra vez, ahora obteniendo también la posición, e imprime solo los pedidos que no están entregados, con la forma "#2 A-1002: En tránsito".

③ Cuenta cuántos imprimiste en ② y, al final, imprime "Sin entregar: ◯".

Editor JavaScript / TypeScript

Ejecutar el código para ver el resultado

Recorrer claves — for...in y por qué no usarlo con arrays

A veces quieres imprimir los nombres de las claves junto con sus valores, como en el perfil de un usuario. Podrías convertir las claves en un array con Object.keys(profile) y recorrerlo con for...of, pero si solo necesitas recorrer las claves, hay una forma más corta.

for...in (una sentencia que recorre una a una las claves de un objeto) se escribe for (const key in profile). La variable contiene la clave como cadena, no el valor, así que el valor se lee con la notación de corchetes, como en profile[key].

const profile = { displayName: "Ana", plan: "premium", posts: 12 };

// key contiene la clave como cadena (no el valor)
for (const key in profile) {
  console.log(`${key}: ${profile[key]}`);
}
// displayName: Ana
// plan: premium
// posts: 12

// Con un array, los índices llegan como cadenas
const stockCounts = [5, 0, 12];
for (const key in stockCounts) {
  console.log(`${typeof key} / ${key + 1}`);
}
// string / 01
// string / 11
// string / 21   ← se concatenan como cadenas, no se suman como números
for...in te entrega claves
Objetoprofilekey es la clavecomo cadenaLee el valor conprofile[key]plan: premiumArraystockCountskey es"0" "1" "2"key + 1concatena cadenasDa "01"
Con un objeto recibes cada clave como cadena, y con un array recibes cada índice como cadena. Sumar 1 en un array no hace una operación aritmética: concatena cadenas.

Si solo lees elementos, como en stockCounts[key], la cadena "1" también te devuelve el valor. Podrías convertirla con Number(key) para usarla en cálculos, pero para los elementos de un array es más sencillo elegir otro bucle desde el principio. La tabla muestra cuándo usar cada una de las tres formas.

SintaxisQué contiene la variableCuándo conviene
for (let i = 0; i < count; i++)El índice como númeroPara calcular con la posición
for (const item of array)El propio elementoPara recorrer solo los elementos
for (const key in object)La clave como cadenaPara las claves de un objeto

No puedes recorrer un objeto con for...of

Si pones un objeto a la derecha de of, como en for (const item of profile), el código se detiene con TypeError: profile is not iterable. Los objetos simples no son iterables: no definen una forma de entregar su contenido uno a uno. Para recorrer también los valores, convierte primero el objeto en un array con Object.entries.

En una pantalla de edición de perfil, compara el perfil antes y después de guardar, e imprime solo los campos que cambiaron. before (los valores anteriores) y after (los valores nuevos) ya están declaradas.

① Prepara una variable que empiece en 0 para contar los campos modificados.

② Usa for...in para recorrer una a una las claves de before.

③ Lee el valor nuevo con la misma clave y, en los campos cuyos valores sean distintos, imprímelos con la forma "city: Yokohama -> Kawasaki" y cuéntalos.

④ Al final, imprime "Campos modificados: ◯".

Editor JavaScript / TypeScript

Ejecutar el código para ver el resultado

Listar todas las combinaciones — bucles anidados

Supón que quieres listar qué productos vende cada tienda, es decir, todas las combinaciones de tienda y producto. Un solo bucle puede recorrer las tiendas o los productos, pero no las dos cosas a la vez. Además, tanto la cantidad de tiendas como la de productos dependen de los datos.

Puedes poner otro bucle directamente dentro del cuerpo de un bucle. El bucle interno se ejecuta completo en cada vuelta del bucle externo, así que la cantidad de veces que se ejecuta el cuerpo interno es la cantidad externa multiplicada por la cantidad interna. El bucle interno también puede leer directamente la variable del bucle externo.

const stores = ["Shibuya", "Yokohama"];
const products = ["Taza", "Cuaderno"];

// En cada vuelta del bucle externo, el bucle interno se ejecuta completo
for (const store of stores) {
  for (const product of products) {
    console.log(`${store} / ${product}`);
  }
}
// Shibuya / Taza
// Shibuya / Cuaderno
// Yokohama / Taza
// Yokohama / Cuaderno
Variables que puede leer el bucle interno
for...of externo (una vuelta por tienda)
  • store — cambia de "Shibuya" a "Yokohama" en cada vuelta
  • El cuerpo externo se ejecuta solo 2 veces
for...of interno (recorre products completo)
  • product — cambia de "Taza" a "Cuaderno" en cada vuelta interna
  • Puede leer directamente el store externo
  • Este cuerpo se ejecuta 2 × 2 = 4 veces
El cuerpo interno puede leer tanto product, del bucle interno, como store, del externo. product, declarada en el bucle interno, solo se puede usar dentro de las llaves internas.

El for...of interno vuelve a empezar desde el principio de products cada vez que cambia la vuelta externa, así que mientras store sigue igual, solo cambia product. Una variable declarada al principio del cuerpo externo también se crea de nuevo en cada vuelta externa. Cómo las llaves limitan dónde se puede usar una variable lo veremos en el artículo sobre el ámbito (scope).

Suma los precios de las líneas de cada pedido. El array orders ya está declarado; cada pedido tiene un número de pedido (id) y un array con los precios de sus líneas (prices).

① Usa un bucle externo para recorrer los pedidos uno a uno.

② Prepara una variable de subtotal para cada pedido, de modo que empiece en 0 cada vez que cambia el pedido.

③ Usa un bucle interno para recorrer los precios de ese pedido y suma cada uno al subtotal.

④ Después del bucle interno, imprime una línea con la forma "A-1001: cantidad 2 / 1760 yenes".

Editor JavaScript / TypeScript

Ejecutar el código para ver el resultado
QUIZ

Verificación de conocimientos

Responde cada pregunta una a una.

Pregunta 1Cuando recorres orderIds.entries() con for...of, ¿qué valor tiene index en la primera vuelta?

Pregunta 2Cuando recorres un array con for...in, ¿qué contiene la variable del bucle?

Pregunta 3Si recorres un array de 3 elementos y otro de 4 en un bucle anidado, ¿cuántas veces se ejecuta el cuerpo interno?