Pregunta 1Cuando recorres orderIds.entries() con for...of, ¿qué valor tiene index en la primera vuelta?
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
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.
| Vuelta | Valor de i y condición | Qué pasa en el cuerpo |
|---|---|---|
| Vuelta 1 | i = 0 / 0 < 3 se cumple | Producto 1: Taza |
| Vuelta 2 | i = 1 / 1 < 3 se cumple | Producto 2: Cuaderno |
| Vuelta 3 | i = 2 / 2 < 3 se cumple | Producto 3: Bolígrafo |
| Inicio de la vuelta 4 | i = 3 / 3 < 3 no se cumple | El 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.
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 obtienes | Qué contiene la variable | Línea impresa |
|---|---|---|
| Elementos con of | El 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 variable | El par de índice y elemento | El 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.
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
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.
| Sintaxis | Qué contiene la variable | Cuándo conviene |
|---|---|---|
| for (let i = 0; i < count; i++) | El índice como número | Para calcular con la posición |
| for (const item of array) | El propio elemento | Para recorrer solo los elementos |
| for (const key in object) | La clave como cadena | Para 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.
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
store— cambia de "Shibuya" a "Yokohama" en cada vuelta- El cuerpo externo se ejecuta solo 2 veces
product— cambia de "Taza" a "Cuaderno" en cada vuelta interna- Puede leer directamente el
storeexterno - Este cuerpo se ejecuta 2 × 2 = 4 veces
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).
Verificación de conocimientos
Responde cada pregunta una a una.
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?