A la lliçó anterior vas aconseguir que el programa decidís. El problema és que decidia sobre una sola tasca: per classificar la urgència de les sis tasques del backlog de Taller Nómada hauries de copiar el mateix bloc sis vegades, i quan la Marta hi afegeixi la setena caldria tornar a tocar el codi. Un bucle resol exactament això: escrius les instruccions una vegada i li dius al programa quantes vegades les ha de repetir. En aquesta lliçó coneixeràs els tres bucles clàssics de JavaScript —for, while i do...while—, aprendràs a recórrer una llista de tasques per índex i dominaràs els quatre patrons que resolen el 90 % dels problemes reals: comptar, acumular, buscar el màxim i comprovar si existeix alguna cosa.
Contingut
- Què és un bucle i per què el necessites
- Anatomia del bucle
for - El bucle
while - El bucle
do...while - Quin triar: taula comparativa
- Recórrer una llista per índex amb
.length - El backlog de Taller Nómada
- Patró acumulador: hores totals del backlog
- Patró comptador: quantes tasques porta cada persona
- Patró màxim/mínim: la tasca més urgent
- Patró bandera: hi ha alguna tasca vençuda?
- Bucles infinits i com evitar-los
for...ofifor...in: un avançament- Errors Habituals i Consells
- Exercicis
- Conclusió
- Què és un bucle i per què el necessites
Un bucle (o iteració) és una estructura de control que executa un bloc de sentències repetidament mentre es compleixi una condició. Cada passada completa pel bloc s'anomena iteració.
Sense bucles, el resum del backlog s'escriu així:
// ✗ Insostenible
console.log(`1. ${titol1} · ${hores1} h`);
console.log(`2. ${titol2} · ${hores2} h`);
console.log(`3. ${titol3} · ${hores3} h`);
// ...i així fins a quarantaAmb un bucle s'escriu una vegada i funciona amb sis tasques, amb quaranta o amb cap. A més, si demà cal afegir la prioritat al resum, canvies una línia en lloc de quaranta.
- Anatomia del bucle
for
forEl for és el bucle de referència quan saps per endavant quantes vegades cal repetir o quan recorres una llista de principi a fi. La seva capçalera conté tres parts separades per ;:
Un exemple mínim: imprimir els tres primers números de tasca.
Sortida:
Què fa cada part, i en quin ordre:
| Part | Quan s'executa | A l'exemple |
|---|---|---|
| Inicialització | Una sola vegada, abans de tot | let i = 1 |
| Condició | Abans de cada iteració | i <= 3 |
| Cos | Si la condició ha estat certa | console.log(...) |
| Actualització | Després de cada iteració | i++ |
El flux complet, pas a pas:
flowchart TD
A["Inicialització<br/>let i = 1"] --> B{"Condició<br/>i <= 3"}
B -->|false| F["Fi del bucle"]
B -->|true| C["Cos<br/>console.log(...)"]
C --> D["Actualització<br/>i++"]
D --> B
Segueix la traça mentalment:
| Pas | i |
Condició i <= 3 |
Què passa |
|---|---|---|---|
| 1 | 1 | true |
Imprimeix "1", després i passa a 2 |
| 2 | 2 | true |
Imprimeix "2", després i passa a 3 |
| 3 | 3 | true |
Imprimeix "3", després i passa a 4 |
| 4 | 4 | false |
El bucle acaba |
Dues observacions fonamentals:
- La condició es comprova ABANS de cada iteració, inclosa la primera. Si comences amb
let i = 5i la condició ési <= 3, el cos no s'executa ni una sola vegada. Això és correcte i desitjable: un bucle sobre una llista buida ha de fer zero iteracions. - L'actualització s'executa DESPRÉS del cos, no abans. Per això a la primera iteració
iencara val 1.
2.1 La variable de control
Per convenció s'anomena i (d'índex), i j, k si n'hi ha més. Es declara amb let, mai amb const: ha de poder canviar a cada actualització.
Declarar-la a la capçalera amb let fa que només existeixi dins del bucle, que és exactament el que vols:
for (let i = 0; i < 3; i++) {
console.log(i);
}
console.log(i); // ✗ ReferenceError: i is not definedSi necessites conèixer el valor final del comptador després del bucle, declara la variable fora. Però gairebé mai no cal: és senyal que en realitat volies un while.
2.2 Variants de la capçalera
Les tres parts són opcionals, encara que els ; no. Aquestes variants són legals:
let i = 0;
for (; i < 3; i++) { } // sense inicialització
for (let j = 10; j > 0; j -= 2) { } // compte enrere de 2 en 2
for (let k = 0, total = 0; k < 3; k++) { } // dues variables, separades per comaComptar cap enrere és habitual quan l'ordre importa:
- El bucle
while
whilewhile repeteix un bloc mentre una condició sigui certa. No té inicialització ni actualització pròpies: te n'encarregues tu.
let horesPendents = 45;
let dies = 0;
const HORES_PER_DIA = 8;
while (horesPendents > 0) {
horesPendents -= HORES_PER_DIA;
dies++;
}
console.log(`El backlog obert ocupa ${dies} dies de feina.`);
// El backlog obert ocupa 6 dies de feina.És exactament el mateix mecanisme que un for amb les tres parts repartides:
let i = 0; // inicialització: fora
while (i < 3) { // condició: a la capçalera
console.log(i);
i++; // actualització: última línia del cos
}Aleshores, per a què serveix while si for fa el mateix? Per als casos en què no saps quantes iteracions caldran. A l'exemple de les hores no sabem per endavant quants dies en sortiran: depèn del total. Escriure-ho amb for obligaria a calcular abans el nombre d'iteracions, que és justament el que volíem esbrinar.
- El bucle
do...while
do...whiledo...while és idèntic a while amb una diferència decisiva: el cos s'executa almenys una vegada, perquè la condició es comprova al final.
let intents = 0;
let tascaTrobada = false;
do {
intents++;
console.log(`Intent de sincronització núm. ${intents}`);
tascaTrobada = intents === 3; // simulem que a la tercera hi surt la vençuda
} while (!tascaTrobada && intents < 5);
console.log(`Sincronitzat després de ${intents} intent/s.`);Fixa't en el ; final: a do...while és obligatori després del while, perquè la sentència acaba aquí. És l'únic dels tres que en porta.
La diferència amb while es veu amb una condició falsa des del principi:
let n = 10;
while (n < 5) {
console.log('while: no executo mai el cos');
}
do {
console.log('do...while: executo el cos una vegada');
} while (n < 5);Sortida:
flowchart LR
subgraph W["while"]
direction TB
W1{"Condició?"} -->|true| W2["Cos"]
W2 --> W1
W1 -->|false| W3["Fi"]
end
subgraph D["do...while"]
direction TB
D1["Cos"] --> D2{"Condició?"}
D2 -->|true| D1
D2 -->|false| D3["Fi"]
end
do...while és el menys utilitzat dels tres. El seu nínxol són els processos que sempre s'han d'intentar una vegada i després decidir si es repeteixen: demanar una dada fins que sigui vàlida, reintentar una operació fallida, generar un identificador fins que no estigui repetit.
- Quin triar: taula comparativa
| Criteri | for |
while |
do...while |
|---|---|---|---|
| Nre. d'iteracions conegut | ✓ Ideal | △ Possible | ✗ Rar |
| Nre. d'iteracions desconegut | △ Possible | ✓ Ideal | ✓ Si va almenys una vegada |
| El cos s'executa com a mínim | 0 vegades | 0 vegades | 1 vegada |
| La condició es comprova | Al principi | Al principi | Al final |
| Comptador visible a la capçalera | ✓ Sí | ✗ No | ✗ No |
| Recórrer una llista completa | ✓ L'opció natural | △ Verbós | ✗ Falla amb llista buida |
| Risc de bucle infinit | Baix | Mitjà | Mitjà |
Necessita ; final |
No | No | Sí |
Regla pràctica: si estàs recorrent una llista o repetint un nombre conegut de vegades, for. Si repeteixes "fins que passi alguna cosa", while. Si a més aquesta cosa només es pot avaluar després del primer intent, do...while.
- Recórrer una llista per índex amb
.length
.lengthPer treballar amb el backlog necessites desar diversos valors en una sola variable. Això és un array: una llista ordenada de valors, escrita entre claudàtors i separada per comes.
const titols = [
'Redissenyar la sala polivalent',
'Cartelleria del taller de serigrafia',
'Actualitzar el web de reserves'
];De moment només necessites tres coses dels arrays; la resta arriba a Arrays: Conceptes Bàsics i Mètodes:
| Necessito | S'escriu | Exemple |
|---|---|---|
| Quants elements hi ha | array.length |
titols.length → 3 |
| L'element a la posició N | array[N] |
titols[0] → 'Redissenyar la sala polivalent' |
| Recórrer-los tots | Un for amb índex |
for (let i = 0; i < titols.length; i++) |
Els índexs comencen a 0. Un array de 3 elements té els índexs 0, 1 i 2. L'últim índex és sempre length - 1, i array[length] dona undefined, no un error. Aquesta és la causa número u d'errors amb bucles.
Sortida:
1. Redissenyar la sala polivalent 2. Cartelleria del taller de serigrafia 3. Actualitzar el web de reserves
Aquesta capçalera —let i = 0, i < array.length, i++— és el patró més repetit de tot JavaScript. Interioritza-la:
- Comença a
0perquè és el primer índex. - Fa servir
<i no<=, perquèlengthés el nombre d'elements, no l'últim índex. - L'
i + 1del missatge és només cosmètic: converteix l'índex en un número d'ordre llegible per a la Marta.
- El backlog de Taller Nómada
Encara no saps crear objectes, així que representarem les sis tasques amb arrays paral·lels: un array per camp, on la posició i de tots ells descriu la mateixa tasca. Aquest codi serà el punt de partida dels exemples següents i dels de les lliçons 02-03 i 02-04.
const AVUI = '2026-09-20';
const ids = [1, 2, 3, 4, 5, 6];
const titols = [
'Redissenyar la sala polivalent',
'Cartelleria del taller de serigrafia',
'Actualitzar el web de reserves',
'Inventari de tintes de serigrafia',
'Guia sobre enquadernació per a residents',
'Pressupost de la fusteria'
];
const responsables = ['Iván', 'Marta', 'Lucía', 'Marta', 'Iván', 'Iván'];
const prioritats = ['alta', 'mitjana', 'alta', 'baixa', 'mitjana', 'alta'];
const estats = ['en-curs', 'pendent', 'pendent', 'feta', 'en-curs', 'pendent'];
const hores = [12, 6, 14, 3, 8, 5];
const datesLimit = [
'2026-09-30', '2026-10-15', '2026-10-02',
'2026-09-12', '2026-11-05', '2026-09-05'
];Llegir la tasca número 3 significa mirar la posició 2 de tots els arrays: titols[2], responsables[2], hores[2]... Així queda el llistat complet:
| i | id | Títol | Responsable | Prioritat | Estat | Hores | Data límit |
|---|---|---|---|---|---|---|---|
| 0 | 1 | Redissenyar la sala polivalent | Iván | alta | en-curs | 12 | 2026-09-30 |
| 1 | 2 | Cartelleria del taller de serigrafia | Marta | mitjana | pendent | 6 | 2026-10-15 |
| 2 | 3 | Actualitzar el web de reserves | Lucía | alta | pendent | 14 | 2026-10-02 |
| 3 | 4 | Inventari de tintes de serigrafia | Marta | baixa | feta | 3 | 2026-09-12 |
| 4 | 5 | Guia sobre enquadernació per a residents | Iván | mitjana | en-curs | 8 | 2026-11-05 |
| 5 | 6 | Pressupost de la fusteria | Iván | alta | pendent | 5 | 2026-09-05 |
Els arrays paral·lels són una solució provisional i fràgil. Si n'ordenes un i els altres no, les dades queden descol·locades sense previ avís. La representació correcta és un array d'objectes, i arribarà al Mòdul 4. Mentrestant serveixen perfectament per aprendre bucles, i patir-ne la fragilitat et farà valorar els objectes quan arribin.
Un llistat complet del backlog combinant bucle i condicional:
for (let i = 0; i < ids.length; i++) {
const marca = estats[i] === 'feta' ? '✓' : '○';
const alerta = datesLimit[i] < AVUI && estats[i] !== 'feta' ? ' ⚠ VENÇUDA' : '';
console.log(
`${marca} [${ids[i]}] ${titols[i]} · ${responsables[i]} · ${prioritats[i]} · ${hores[i]} h${alerta}`
);
}Sortida:
○ [1] Redissenyar la sala polivalent · Iván · alta · 12 h ○ [2] Cartelleria del taller de serigrafia · Marta · mitjana · 6 h ○ [3] Actualitzar el web de reserves · Lucía · alta · 14 h ✓ [4] Inventari de tintes de serigrafia · Marta · baixa · 3 h ○ [5] Guia sobre enquadernació per a residents · Iván · mitjana · 8 h ○ [6] Pressupost de la fusteria · Iván · alta · 5 h ⚠ VENÇUDA
Ja tens les dues estructures del mòdul treballant juntes: el bucle recorre, el condicional decideix. La tasca 4 no es marca com a vençuda tot i que la seva data ja ha passat, perquè està feta: la regla R10 exigeix totes dues condicions.
- Patró acumulador: hores totals del backlog
L'acumulador és una variable declarada abans del bucle que va sumant (o concatenant) a cada iteració.
let totalHores = 0;
let horesObertes = 0;
for (let i = 0; i < hores.length; i++) {
totalHores += hores[i];
if (estats[i] !== 'feta') {
horesObertes += hores[i];
}
}
console.log(`Hores estimades totals: ${totalHores} h`); // 48 h
console.log(`Hores de feina oberta: ${horesObertes} h`); // 45 hEls tres elements del patró:
- Inicialitzar fora del bucle, i amb el valor neutre:
0per a sumes,1per a productes,''per a textos. Si el declares a dins, es reinicia a cada iteració i el resultat és sempre l'últim valor. - Acumular a dins, amb
+=. - Fer-lo servir després, quan el bucle ha acabat.
Declarar-lo amb let és obligatori: const impediria reassignar-lo.
Un acumulador amb condició —com horesObertes— és la base de tots els informes de la Marta: sumar només allò que compleix un criteri. Al Mòdul 4 això s'escriurà en una línia amb reduce, però el mecanisme que aprens aquí és exactament el mateix.
- Patró comptador: quantes tasques porta cada persona
Un comptador és un acumulador que suma 1 en lloc d'un valor. Amb tres persones a l'equip n'hi ha prou amb tres comptadors i una cadena else if:
let tasquesIvan = 0;
let tasquesMarta = 0;
let tasquesLucia = 0;
for (let i = 0; i < responsables.length; i++) {
if (responsables[i] === 'Iván') {
tasquesIvan++;
} else if (responsables[i] === 'Marta') {
tasquesMarta++;
} else if (responsables[i] === 'Lucía') {
tasquesLucia++;
} else {
console.warn(`Responsable no reconegut a la tasca ${ids[i]}: ${responsables[i]}`);
}
}
console.log(`Iván: ${tasquesIvan} tasques`); // Iván: 3 tasques
console.log(`Marta: ${tasquesMarta} tasques`); // Marta: 2 tasques
console.log(`Lucía: ${tasquesLucia} tasques`); // Lucía: 1 tasquesEl repartiment confirma el diagnòstic de la lliçó 01-08: l'Iván està sobrecarregat i la Lucía té marge. Exactament el tipus de dada que la Marta no podia veure amb la seva paret de notes adhesives.
Aquest codi fa una olor evident: tres variables gairebé idèntiques i una cadena d'else if que creix amb cada persona nova. Si demà entra algú a l'equip, cal tocar quatre llocs. La solució neta són els bucles imbricats sobre un array de responsables (lliçó 02-04) i, definitivament, un objecte comptador al Mòdul 4. Reconèixer la incomoditat ara forma part de l'aprenentatge.
Combinant comptador i acumulador obtenim la càrrega real de l'Iván, necessària per a la regla R7 (ningú no supera 40 h):
let horesIvan = 0;
for (let i = 0; i < responsables.length; i++) {
if (responsables[i] === 'Iván' && estats[i] !== 'feta') {
horesIvan += hores[i];
}
}
console.log(`Càrrega oberta de l'Iván: ${horesIvan} h de 40`); // 25 h de 40
if (horesIvan > 40) {
console.error('R7 incomplerta: Iván supera les 40 hores setmanals.');
} else {
console.log(`Marge disponible: ${40 - horesIvan} h`); // Marge disponible: 15 h
}
- Patró màxim/mínim: la tasca més urgent
Per trobar el valor extrem d'una llista es desa un candidat provisional i se substitueix cada vegada que n'apareix un de millor. Busquem la tasca oberta amb la data límit més propera:
let dataMesPropera = '';
let titolMesUrgent = '';
let idMesUrgent = 0;
for (let i = 0; i < datesLimit.length; i++) {
const esCandidata = estats[i] !== 'feta';
const esLaPrimera = dataMesPropera === '';
const vencAbans = datesLimit[i] < dataMesPropera;
if (esCandidata && (esLaPrimera || vencAbans)) {
dataMesPropera = datesLimit[i];
titolMesUrgent = titols[i];
idMesUrgent = ids[i];
}
}
console.log(`Més urgent: [${idMesUrgent}] ${titolMesUrgent} (venç ${dataMesPropera})`);
// Més urgent: [6] Pressupost de la fusteria (venç 2026-09-05)Les tres claus del patró:
- El valor inicial ha de ser impossible o marcar "encara no hi ha candidat". Aquí fem servir
'', i la variableesLaPrimeradetecta aquest cas. L'alternativa habitual —inicialitzar amb el primer element— no serveix aquí perquè el primer element podria estar fet i quedar descartat. - La comparació de dates ISO com a text funciona, com ja saps des de la lliçó 01-08.
- Cal arrossegar totes les dades del guanyador alhora. Com que els camps són en arrays paral·lels, en trobar un candidat millor cal copiar-ne la data, el títol i l'id al mateix bloc. Oblidar-ne un produeix un resultat barrejat: la data d'una tasca amb el títol d'una altra. És la fragilitat dels arrays paral·lels en acció.
Per al màxim el patró és idèntic invertint la comparació. La tasca amb més hores:
let maxHores = -1;
let titolMesLlarg = '';
for (let i = 0; i < hores.length; i++) {
if (hores[i] > maxHores) {
maxHores = hores[i];
titolMesLlarg = titols[i];
}
}
console.log(`La més llarga: ${titolMesLlarg} (${maxHores} h)`);
// La més llarga: Actualitzar el web de reserves (14 h)-1 com a valor inicial és segur perquè la regla R3 garanteix que cap tasca no té hores negatives. Inicialitzar a 0 també funcionaria, però -1 deixa clar que és un sentinella i no una dada.
- Patró bandera: hi ha alguna tasca vençuda?
Una bandera (flag) és una variable booleana que comença en false i es posa a true tan bon punt passa el que busques. Serveix per respondre preguntes de sí o no sobre tota la llista.
let hiHaVencudes = false;
let quantesVencudes = 0;
for (let i = 0; i < datesLimit.length; i++) {
if (datesLimit[i] < AVUI && estats[i] !== 'feta') {
hiHaVencudes = true;
quantesVencudes++;
}
}
if (hiHaVencudes) {
console.error(`Atenció: ${quantesVencudes} tasca/es vençuda/es al tauler.`);
} else {
console.log('Cap tasca vençuda. Tot en termini.');
}
// Atenció: 1 tasca/es vençuda/es al tauler.La bandera contrària —comprovar que totes compleixen alguna cosa— s'inicialitza al revés, en true, i es posa a false tan bon punt apareix un contraexemple:
let totesAssignades = true;
for (let i = 0; i < responsables.length; i++) {
if (responsables[i] === null) {
totesAssignades = false;
}
}
console.log(totesAssignades ? 'Totes les tasques tenen responsable.' : 'Hi ha tasques sense assignar.');| Pregunta | Valor inicial | Es canvia a | Quan |
|---|---|---|---|
| Existeix alguna que compleixi X? | false |
true |
En trobar la primera que compleix |
| Compleixen totes X? | true |
false |
En trobar la primera que no compleix |
En tots dos casos el bucle continua recorrent la llista encara que la resposta ja es conegui. Això és feina malgastada, i a la lliçó 02-04 aprendràs a tallar en sec amb break.
- Bucles infinits i com evitar-los
Un bucle infinit és aquell la condició del qual no arriba mai a ser falsa. Al navegador la pestanya es congela; a Node.js el procés es queda penjat fins que el mates amb Ctrl + C.
Les tres causes habituals:
Oblidar l'actualització.
Actualitzar en la direcció equivocada.
Modificar el comptador dins del cos sense adonar-te'n.
// ✗ i torna a 0 a la primera tasca sense assignar i no en surt mai
for (let i = 0; i < responsables.length; i++) {
if (responsables[i] === null) {
i = 0;
}
}Com protegir-te:
- Comprova abans d'executar que la condició pot arribar a ser falsa. Localitza quina variable apareix a la condició i verifica que el cos o l'actualització la mouen cap al final.
- No modifiquis la variable de control dins del cos. Si creus que ho necessites, gairebé segur que volies un
while. - Afegeix un límit de seguretat en bucles la condició dels quals depèn de dades externes:
let intents = 0;
const MAX_INTENTS = 1000;
while (!hiHaVencudes && intents < MAX_INTENTS) {
intents++;
// ...
}
if (intents === MAX_INTENTS) {
console.error('Límit de seguretat assolit: revisa la condició del bucle.');
}- Si ja has penjat la pestanya, tanca-la i fes servir
node fitxer.jsambCtrl + Cper provar bucles dubtosos: és molt més fàcil d'aturar.
Hi ha una excepció legítima: while (true) amb una sortida explícita a dins. Es fa servir en bucles de reintent i sempre porta un break, que veuràs a la lliçó vinent.
for...of i for...in: un avançament
for...of i for...in: un avançamentJavaScript modern té dos bucles més, pensats per recórrer col·leccions sense gestionar l'índex a mà. Els presentem aquí perquè els reconeguis; el detall sobre arrays és a Iteració sobre Arrays.
for...of recorre els valors d'un array (o de qualsevol cosa iterable, com un text):
Més net que el for clàssic quan només necessites el valor i no la posició. Fixa't que la variable pot ser const, perquè a cada iteració es crea de nou. El problema en el nostre cas és que amb arrays paral·lels sí que necessitem l'índex per consultar els altres camps, així que continuarem fent servir el for clàssic durant aquest mòdul.
for...in recorre les claus (en un array, els índexs, i a més com a text):
for (const i of titols) { } // valors
for (const i in titols) { // índexs, però '0', '1', '2'... com a strings
console.log(i + 1); // ✗ '01', '11', '21' — concatena, no suma
}Aquest parany de la concatenació és el motiu principal de la norma universal: for...in és per a objectes, no per a arrays. Recorre també propietats heretades i no en garanteix l'ordre. Quan arribis als objectes al Mòdul 4 li trobaràs el seu lloc.
| Bucle | Què et dona | Fes-lo servir per a |
|---|---|---|
for (let i = 0; ...) |
L'índex numèric | Arrays quan necessites la posició |
for...of |
El valor | Arrays i textos quan només vols el valor |
for...in |
La clau com a text | Objectes, no arrays |
Errors Habituals i Consells
Fer servir <= amb .length.
A l'última volta titols[6] val undefined, i el resum imprimeix "undefined · undefined". Amb .length va sempre <.
Començar a 1. for (let i = 1; i < titols.length; i++) es salta la primera tasca silenciosament. Els índexs comencen a 0.
Declarar l'acumulador dins del bucle.
for (let i = 0; i < hores.length; i++) {
let total = 0; // ✗ es reinicia a cada volta
total += hores[i];
}L'acumulador val sempre el mateix que l'últim element, i a més desapareix en sortir. Va abans del bucle.
Confondre l'índex amb el valor. hores[i] és el nombre d'hores; i és la posició. totalHores += i suma 0+1+2+3+4+5 = 15, un nombre que sembla plausible i no ho és. Quan un total surti estrany, comprova això primer.
Modificar .length dins del bucle. Afegir o treure elements mentre recorres canvia la condició sobre la marxa i produeix salts o bucles infinits. Recorre per llegir; construeix la llista modificada a part.
Oblidar el ; de do...while. És l'únic que en porta, i l'ASI que vas veure a la lliçó 01-04 no sempre et salva.
Consell: posa un bon nom a la variable de control. i està acceptat universalment per a índexs, però si el bucle és llarg, let indexTasca es llegeix millor al cap de tres mesos.
Consell: si el cos del bucle passa de vint línies, alguna cosa va malament. Al Mòdul 3 aprendràs a extreure aquesta lògica a funcions; de moment, com a mínim separa els càlculs en variables amb nom abans de l'if.
Consell: imprimeix la traça quan alguna cosa no quadri. Un console.log(i, titols[i], totalHores) com a primera línia del cos et mostra l'estat a cada volta i resol la majoria de les fallades en segons.
Exercicis
Exercici 1 — Resum del taller
Partint del backlog de la secció 7, escriu un únic bucle for que calculi i mostri:
- El nombre total de tasques.
- Quantes estan
pendent, quantesen-cursi quantesfeta. - El percentatge d'avenç, entès com a tasques fetes sobre el total, arrodonit a un decimal.
Recorda de la lliçó 01-06 que Math.round(x * 10) / 10 arrodoneix a un decimal.
Exercici 2 — Compte enrere de venciments
Escriu un bucle while que, partint d'horesObertes = 45 i una jornada de 8 hores, calculi quants dies laborables calen per buidar el backlog, imprimint a cada volta les hores que van quedant. Després respon: per què aquí while és millor elecció que for?
Exercici 3 — Tasca de més pes
Fent servir la conversió de prioritat a pes de la lliçó anterior (alta = 3, mitjana = 2, baixa = 1), calcula per a cada tasca oberta un índex d'esforç igual a pes * hores, i troba la tasca oberta amb l'índex més alt. Mostra el llistat complet amb el seu índex i, al final, la guanyadora.
Solucions
Exercici 1
let pendents = 0;
let enCurs = 0;
let fetes = 0;
for (let i = 0; i < estats.length; i++) {
if (estats[i] === 'pendent') {
pendents++;
} else if (estats[i] === 'en-curs') {
enCurs++;
} else if (estats[i] === 'feta') {
fetes++;
} else {
console.warn(`Estat desconegut a la tasca ${ids[i]}: ${estats[i]}`);
}
}
const total = estats.length;
const avenc = Math.round((fetes / total) * 100 * 10) / 10;
console.log(`Total de tasques: ${total}`); // 6
console.log(`Pendents: ${pendents}`); // 3
console.log(`En curs: ${enCurs}`); // 2
console.log(`Fetes: ${fetes}`); // 1
console.log(`Avenç: ${avenc} %`); // 16.7 %Tres comptadors actualitzats en el mateix recorregut: recórrer la llista una sola vegada i calcular tot el que necessitis en aquella passada és sempre preferible a fer tres bucles. L'else final protegeix contra estats no previstos, aplicant la norma de la lliçó 02-01 de tancar sempre les cadenes.
El càlcul del percentatge mereix atenció: fetes / total dona 0.1666...; multiplicar per 100 dona 16.666...; i el truc de multiplicar per 10, arrodonir i dividir entre 10 deixa 16.7 com a nombre. toFixed(1) donaria el text '16.7', i si més endavant el sumessis a una altra cosa obtindries una concatenació en lloc d'una suma.
Exercici 2
let horesObertes = 45;
const HORES_PER_DIA = 8;
let dies = 0;
while (horesObertes > 0) {
dies++;
horesObertes -= HORES_PER_DIA;
const restants = horesObertes > 0 ? horesObertes : 0;
console.log(`Dia ${dies}: queden ${restants} h`);
}
console.log(`El backlog obert ocupa ${dies} dia/es laborable/s.`);Sortida:
Dia 1: queden 37 h Dia 2: queden 29 h Dia 3: queden 21 h Dia 4: queden 13 h Dia 5: queden 5 h Dia 6: queden 0 h El backlog obert ocupa 6 dia/es laborable/s.
El ternari evita mostrar -3 h a l'última volta, perquè restar 8 a 5 se salta el zero.
Per què while: el nombre d'iteracions no es coneix abans de començar; és precisament el que el bucle calcula. Amb un for caldria escriure for (let d = 0; d < Math.ceil(45 / 8); d++), és a dir, resoldre el problema a la capçalera per després simular que el resolem al cos. La regla es compleix: quan la condició d'aturada depèn d'un estat que evoluciona, while.
Exercici 3
let maxEsforc = -1;
let titolGuanyadora = '';
for (let i = 0; i < ids.length; i++) {
if (estats[i] === 'feta') {
console.log(`[${ids[i]}] ${titols[i]} — tancada, no puntua`);
} else {
let pes;
if (prioritats[i] === 'alta') {
pes = 3;
} else if (prioritats[i] === 'mitjana') {
pes = 2;
} else {
pes = 1;
}
const esforc = pes * hores[i];
console.log(`[${ids[i]}] ${titols[i]} — esforç ${esforc}`);
if (esforc > maxEsforc) {
maxEsforc = esforc;
titolGuanyadora = titols[i];
}
}
}
console.log(`\nMés esforç: ${titolGuanyadora} (${maxEsforc})`);Sortida:
[1] Redissenyar la sala polivalent — esforç 36 [2] Cartelleria del taller de serigrafia — esforç 12 [3] Actualitzar el web de reserves — esforç 42 [4] Inventari de tintes de serigrafia — tancada, no puntua [5] Guia sobre enquadernació per a residents — esforç 16 [6] Pressupost de la fusteria — esforç 15 Més esforç: Actualitzar el web de reserves (42)
Tres detalls que convé notar. Primer, let pes; es declara dins del bucle a propòsit: és un valor diferent a cada iteració, no un acumulador, així que s'ha de reiniciar. Segon, maxEsforc i titolGuanyadora sí que van fora, perquè han de sobreviure entre voltes. I tercer, aquesta cadena de tres else if repetida a cada iteració és exactament el cas que resoldrà el switch de la lliçó vinent de manera més compacta.
Conclusió
Ja saps repetir. Coneixes el for amb la seva triple capçalera —inicialització, condició i actualització— i l'ordre exacte en què s'executen; el while, per quan no saps quantes voltes caldran; i el do...while, per allò que s'ha d'intentar almenys una vegada. Saps recórrer una llista amb for (let i = 0; i < array.length; i++), que és la capçalera més escrita de tot JavaScript, i per què els índexs van de 0 a length - 1.
Sobretot, domines els quatre patrons que resolen gairebé qualsevol recorregut: l'acumulador per sumar hores, el comptador per repartir tasques per persona, el màxim/mínim per trobar la més urgent i la bandera per respondre si n'hi ha alguna de vençuda. Tots quatre comparteixen la mateixa estructura: una variable declarada abans del bucle, actualitzada a dins i consultada després. I saps reconèixer i evitar un bucle infinit abans de congelar la pestanya.
Aplicat a Nómada Tasques, ja pots generar l'informe que la Marta no va tenir mai: 48 hores estimades en total, 45 de feina oberta, un 16,7 % d'avenç, una tasca vençuda i una càrrega molt desigual —l'Iván amb tres tasques i 25 hores davant de l'única de la Lucía—.
Hauràs notat dues incomoditats. Una: convertir prioritat en un pes obligava a repetir la mateixa cadena d'else if una vegada i una altra. Dues: els bucles continuen recorrent la llista sencera encara que la resposta ja es conegui. La primera s'ataca a Sentències Switch, on aprendràs una construcció pensada exactament per triar entre diversos valors d'una mateixa variable, i la segona a la lliçó següent, amb break i continue.
Curs de JavaScript: De Principiant a Avançat
Mòdul 1: Introducció a JavaScript
- Què és JavaScript?
- Configuració del teu Entorn de Desenvolupament
- El teu Primer Programa en JavaScript
- Sintaxi i Conceptes Bàsics de JavaScript
- Variables i Tipus de Dades
- Operadors Bàsics
- Conversió de Tipus i Comparacions
- El Projecte del Curs: Nómada Tasques
Mòdul 2: Estructures de Control
- Sentències Condicionals
- Bucles: for, while, do-while
- Sentències Switch
- Control del Flux: break, continue i Bucles Imbricats
- Gestió d'Errors amb try-catch
Mòdul 3: Funcions
- Definició i Crida de Funcions
- Expressions de Funció i Funcions Fletxa
- Paràmetres i Valors de Retorn
- Àmbit i Closures
- Hoisting i el Context d'Execució
- Funcions d'Ordre Superior
- Recursivitat
Mòdul 4: Objectes i Arrays
- Introducció als Objectes
- Mètodes d'Objecte i la Paraula Clau
this - Arrays: Conceptes Bàsics i Mètodes
- Iteració sobre Arrays
- Cercar, Ordenar i Agregar Dades: find, sort i reduce
- Desestructuració d'Arrays
- Desestructuració d'Objectes, Spread i Rest
- JSON i Còpies d'Objectes
Mòdul 5: Objectes i Funcions Avançades
- Prototips i Herència
- Classes i Programació Orientada a Objectes
- Encapsulació: Getters, Setters i Camps Privats
- Mòduls i Importació/Exportació
- JavaScript Asíncron: Callbacks
- Promeses i Async/Await
- El Bucle d'Esdeveniments i la Cua de Microtasques
- Iteradors i Generadors
Mòdul 6: El Model d'Objectes del Document (DOM)
- Introducció al DOM
- Selecció i Manipulació d'Elements del DOM
- Gestió d'Esdeveniments
- Propagació, Delegació i Esdeveniments Personalitzats
- Creació i Eliminació d'Elements del DOM
- Renderitzat de Llistes i Plantilles HTML
- Gestió i Validació de Formularis
Mòdul 7: APIs del Navegador i Temes Avançats
- Emmagatzematge Local i de Sessió
- Fetch API i AJAX
- Peticions Robustes: Errors, Timeouts i AbortController
- WebSockets
- Service Workers i Aplicacions Web Progressives (PWAs)
- APIs del Navegador Essencials
- Introducció a WebAssembly
Mòdul 8: Proves i Depuració
- Depuració de JavaScript
- Qualitat de Codi: ESLint, Prettier i Convencions
- Proves Unitàries amb Jest
- Dobles de Prova: Mocks, Stubs i Spies
- Proves d'Integració
- Proves d'Extrem a Extrem amb Cypress
Mòdul 9: Rendiment i Optimització
- Mesurar Abans d'Optimitzar: DevTools i Web Vitals
- Optimització del Rendiment de JavaScript
- Gestió de Memòria
- Manipulació Eficient del DOM
- Càrrega Diferida i Divisió de Codi
Mòdul 10: Frameworks i Llibreries de JavaScript
- Per Què Existeixen els Frameworks
- Introducció a React
- Gestió d'Estat amb Redux
- Conceptes Bàsics de Vue.js
- Conceptes Bàsics d'Angular
- Triar el Framework Adequat
