La lliçó anterior va acabar amb una limitació: pesDePrioritat i descriureTasca són declaracions amb nom fix, disponibles sempre i sempre iguals. Però a Nómada Tasques necessitaràs alguna cosa més flexible: una taula que associï cada estat amb la funció que el formata, una llista de validadors que es recorri amb un bucle, o una funció que es triï en temps d'execució segons el que hagi demanat la Marta. Tot això és possible perquè en JavaScript una funció és un valor, exactament igual que un nombre o un text: es pot desar en una variable, ficar en un array, posar dins d'un objecte i passar com a argument. En aquesta lliçó aprendràs les dues maneres d'escriure funcions com a valors —l'expressió de funció i la funció fletxa—, quan fer servir cadascuna i quines diferències reals hi ha entre elles.

Contingut

  1. Les funcions són valors de primera classe
  2. L'expressió de funció
  3. Expressió de funció amb nom
  4. La funció fletxa: la sintaxi completa
  5. Retornar un objecte literal des d'una fletxa
  6. Taula comparativa: declaració vs expressió vs fletxa
  7. La fletxa i this: el que necessites saber avui
  8. Un objecte de formatadors per a Nómada Tasques
  9. Una taula de validadors recorrible
  10. IIFE: la funció que es crida a si mateixa en néixer
  11. Quan triar cada forma
  12. Errors Habituals i Consells
  13. Exercicis
  14. Conclusió

  1. Les funcions són valors de primera classe

Dir que les funcions són ciutadans de primera classe (first-class citizens) significa que el llenguatge les tracta com qualsevol altre valor. Comprova-ho amb la funció de la lliçó anterior:

function pesDePrioritat(prioritat) {
  if (prioritat === 'alta') return 3;
  if (prioritat === 'mitjana') return 2;
  if (prioritat === 'baixa') return 1;
  return 0;
}

// 1. Es pot assignar a una variable
const calcularPes = pesDePrioritat;
console.log(calcularPes('alta'));       // 3

// 2. Es pot ficar en un array
const operacions = [pesDePrioritat];
console.log(operacions[0]('mitjana'));  // 2

// 3. Es pot desar en un objecte
const utilitats = { pes: pesDePrioritat };
console.log(utilitats.pes('baixa'));    // 1

// 4. Es pot inspeccionar
console.log(typeof pesDePrioritat);     // 'function'
console.log(pesDePrioritat.name);       // 'pesDePrioritat'
console.log(pesDePrioritat.length);     // 1  (nombre de paràmetres declarats)

Fixa't en la línia const calcularPes = pesDePrioritat;: no hi ha parèntesis. No s'està cridant la funció, s'està copiant la referència a la funció. Ara hi ha dos noms apuntant al mateix tros de codi. Això connecta directament amb el que vas aprendre a Variables i Tipus de Dades: les funcions són valors de referència, com els objectes i els arrays.

console.log(calcularPes === pesDePrioritat);   // true → és el mateix objecte funció

I aquest és el mecanisme que fa possible tot el que ve després: si una funció és un valor, es pot passar a una altra funció (ho veuràs a Funcions d'Ordre Superior) i es pot triar en temps d'execució.

  1. L'expressió de funció

Una expressió de funció és una funció escrita al lloc on aniria un valor. La més habitual és assignar-la a una constant:

const estaVencuda = function (dataLimit, estat, avui) {
  return dataLimit < avui && estat !== 'feta';
};

console.log(estaVencuda('2026-09-05', 'pendent', '2026-09-20'));   // true

Tres detalls de sintaxi que convé marcar:

  • Després de function no hi ha nom. Es diu que és una funció anònima.
  • La constant estaVencuda és la que dóna nom pràctic a la funció.
  • Hi ha punt i coma al final, perquè tota la línia és una assignació (una sentència), no una declaració.

La diferència pràctica més important amb la declaració és quan existeix:

console.log(declarada('alta'));   // 3  ✓ funciona
function declarada(p) { return p === 'alta' ? 3 : 1; }

console.log(expressada('alta'));  // ✗ ReferenceError: Cannot access 'expressada' before initialization
const expressada = function (p) { return p === 'alta' ? 3 : 1; };

Una declaració de funció està a punt abans que comenci l'execució; una expressió assignada a const o let no existeix fins que la línia s'executa. El mecanisme complet (el hoisting i la zona morta temporal) l'estudiaràs a Hoisting i el Context d'Execució. La conseqüència pràctica d'avui: amb expressions, defineix abans d'usar.

Aquesta restricció, que sembla un inconvenient, en realitat és un avantatge: obliga a un ordre de lectura natural de dalt a baix i evita l'estil desordenat en què les funcions apareixen després d'haver-se fet servir.

  1. Expressió de funció amb nom

Es pot posar un nom a la funció i a més assignar-la a una variable. S'anomena named function expression:

const calcularUrgencia = function calcularUrgenciaInterna(prioritat, diesRestants) {
  if (diesRestants < 0) return 100;
  return pesDePrioritat(prioritat) * 10 - diesRestants;
};

Per a què serveix aquest nom intern, si per cridar-la es fa servir calcularUrgencia?

Avantatge Explicació
Traces d'error llegibles Al stack d'un Error apareix calcularUrgenciaInterna en lloc de <anonymous>
Autoreferència Dins del cos pots cridar-te a tu mateixa per aquest nom, útil en recursivitat (vegeu Recursivitat)
No contamina fora calcularUrgenciaInterna només existeix dins del cos; a fora dóna ReferenceError
console.log(calcularUrgencia.name);          // 'calcularUrgenciaInterna'
console.log(typeof calcularUrgenciaInterna); // ✗ ReferenceError

A la pràctica es fa servir poc, perquè els motors moderns ja infereixen el nom de la variable:

const estaVencuda = function (d, e, a) { return d < a && e !== 'feta'; };
console.log(estaVencuda.name);   // 'estaVencuda'  ← inferit de la constant

  1. La funció fletxa: la sintaxi completa

La funció fletxa (arrow function), introduïda a ES2015, és una manera més breu d'escriure una expressió de funció. La seva sintaxi té diverses formes segons el que necessitis, i convé conèixer-les totes perquè les veuràs barrejades en qualsevol codi real.

4.1 Cos de bloc

És la traducció literal d'una expressió de funció: treus function i poses => entre els parèntesis i les claus.

const estaVencuda = (dataLimit, estat, avui) => {
  return dataLimit < avui && estat !== 'feta';
};

Amb claus, el return és obligatori si vols retornar alguna cosa.

4.2 Retorn implícit

Si el cos és una sola expressió, pots treure les claus i el return. El valor d'aquesta expressió es retorna automàticament:

const estaVencuda = (dataLimit, estat, avui) => dataLimit < avui && estat !== 'feta';

Aquesta és la forma que més veuràs al codi professional per a funcions petites.

4.3 Un sol paràmetre

Amb exactament un paràmetre, els parèntesis són opcionals:

const enMajuscules = text => text.toUpperCase();
const esFeta       = estat => estat === 'feta';

Molts equips configuren el seu linter per exigir sempre els parèntesis ((text) => ...), perquè així afegir un segon paràmetre no obliga a reescriure la línia. A Qualitat de Codi veuràs com s'automatitza aquesta decisió.

4.4 Sense paràmetres

Els parèntesis buits són obligatoris:

const dataAvui = () => '2026-09-20';
console.log(dataAvui());   // 2026-09-20

4.5 Resum de formes

Forma Sintaxi Quan fer-la servir
Bloc (a, b) => { ...; return x; } Diverses sentències, guardes, variables internes
Retorn implícit (a, b) => a + b Una sola expressió
Un paràmetre a => a * 2 Transformacions simples
Sense paràmetres () => 'valor' Constants calculades, fàbriques
Objecte literal (a) => ({ clau: a }) Vegeu l'apartat següent

  1. Retornar un objecte literal des d'una fletxa

Aquí hi ha un parany sintàctic que confon tothom la primera vegada. Això no funciona com esperes:

const resumir = (titol, hores) => { titol: titol, hores: hores };
console.log(resumir('Actualitzar el web de reserves', 14));   // undefined

El motor interpreta aquestes claus com un bloc de codi, no com un objecte literal. Dins del bloc, titol: sembla una etiqueta (com els break etiqueta de break, continue i Bucles Imbricats), no hi ha return, i la funció retorna undefined.

La solució és embolcallar l'objecte entre parèntesis, perquè el motor sàpiga que és una expressió:

const resumir = (titol, hores) => ({ titol: titol, hores: hores });
console.log(resumir('Actualitzar el web de reserves', 14));
// { titol: 'Actualitzar el web de reserves', hores: 14 }

Regla per recordar-ho: claus = bloc; parèntesis + claus = objecte.

flowchart TD
    A["(x) => { ... }"] --> B["Les claus són un BLOC<br/>Necessites return explícit"]
    C["(x) => ({ ... })"] --> D["Els parèntesis forcen EXPRESSIÓ<br/>Retorna l'objecte"]

  1. Taula comparativa: declaració vs expressió vs fletxa

Aquesta és la taula que convé tenir a mà fins que les diferències se't quedin gravades:

Aspecte Declaració
function f() {}
Expressió
const f = function () {}
Fletxa
const f = () => {}
Es pot cridar abans de definir-la Sí (hoisting complet) No (TDZ de const/let) No (TDZ de const/let)
Té nom propi Sí, sempre Opcional (anònima o amb nom) No; s'infereix de la variable
this propi No: hereta el de l'entorn
Objecte arguments No
Es pot fer servir amb new No (TypeError)
Retorn implícit No No Sí, si el cos és una expressió
Sintaxi més breu No No
Ús típic Funcions principals del mòdul Funcions assignades condicionalment Callbacks i funcions d'una línia

Tres d'aquestes files necessiten aclariment immediat:

  • arguments és un objecte llegat que conté tots els arguments rebuts encara que no estiguin declarats com a paràmetres. El veuràs a Paràmetres i Valors de Retorn, juntament amb el seu substitut modern, els paràmetres rest. Les fletxes no el tenen.
  • new serveix per crear objectes amb funcions constructores; és matèria de Prototips i Herència. Amb una fletxa dóna error, i això és deliberat.
  • this es mereix el seu propi apartat.

  1. La fletxa i this: el que necessites saber avui

this és una paraula clau el valor de la qual depèn de com es crida la funció. És un tema amb prou matisos per a una lliçó sencera, i la té: Mètodes d'Objecte i this. Avui només necessites gravar-te una frase:

Una funció fletxa no té el seu propi this: fa servir el de l'àmbit on va ser escrita.

D'aquí se'n deriven les dues conseqüències pràctiques que et trobaràs:

  1. No facis servir una fletxa com a mètode d'un objecte quan el mètode necessiti accedir a les dades d'aquest objecte. La fletxa no "veurà" l'objecte.
  2. Sí que has de fer servir una fletxa per a funcions que es passen a una altra funció (callbacks, gestors d'esdeveniments del Mòdul 6), perquè conserva el this del voltant i això sol ser justament el que vols.

Un exemple mínim, només perquè reconeguis el símptoma quan aparegui:

const panell = {
  titol: 'Backlog de Taller Nómada',

  ambFuncio: function () {
    return this.titol;         // 'Backlog de Taller Nómada'
  },

  ambFletxa: () => {
    return this.titol;         // undefined  ← la fletxa no veu l'objecte
  }
};

console.log(panell.ambFuncio());   // Backlog de Taller Nómada
console.log(panell.ambFletxa());   // undefined

No intentis entendre ara per què: només recorda el patró. A 04-02 el desmuntaràs peça a peça. Res del que escriguis en aquest mòdul depèn de this.

  1. Un objecte de formatadors per a Nómada Tasques

Aquí és on les funcions com a valors comencen a pagar. Al Mòdul 2 formataves cada camp amb switch o cadenes d'if repartits pel fitxer. Ara pots agrupar tots els formatadors en un sol objecte, amb l'avantatge que cadascun es pot substituir, reutilitzar o provar per separat.

'use strict';

const AVUI = '2026-09-20';

const MESOS = ['gen', 'feb', 'mar', 'abr', 'mai', 'jun',
               'jul', 'ago', 'set', 'oct', 'nov', 'des'];

const formatadors = {
  // '2026-09-30' → '30 set 2026'
  data: (iso) => {
    const [any, mes, dia] = [iso.slice(0, 4), iso.slice(5, 7), iso.slice(8, 10)];
    return `${Number(dia)} ${MESOS[Number(mes) - 1]} ${any}`;
  },

  // 'en-curs' → 'En curs'
  estat: (estat) => {
    if (estat === 'pendent') return 'Pendent';
    if (estat === 'en-curs') return 'En curs';
    if (estat === 'feta') return 'Feta';
    return 'Desconegut';
  },

  // 'alta' → '🔴 Alta'
  prioritat: (prioritat) => {
    if (prioritat === 'alta') return '🔴 Alta';
    if (prioritat === 'mitjana') return '🟠 Mitjana';
    if (prioritat === 'baixa') return '🟢 Baixa';
    return '⚪ Sense prioritat';
  },

  // 7.5 → '7,5 h'
  hores: (hores) => `${String(hores).replace('.', ',')} h`,

  // null → '—'
  responsable: (nom) => nom ?? '—'
};

console.log(formatadors.data('2026-09-30'));      // 30 set 2026
console.log(formatadors.estat('en-curs'));        // En curs
console.log(formatadors.prioritat('alta'));       // 🔴 Alta
console.log(formatadors.hores(7.5));              // 7,5 h
console.log(formatadors.responsable(null));       // —

Explicació del que aporta aquesta estructura:

  • Un sol punt de canvi per a tota la presentació. Si la Marta demana que les dates es mostrin com 30/09/2026, toques una línia.
  • Es tria el formatador amb una variable. formatadors[camp](valor) permet formatar un camp el nom del qual no coneixes fins que s'executa el programa. Això amb switch no es podia fer.
  • Cada formatador és independent. Al Mòdul 8 podràs provar formatadors.data sense engegar la resta de l'aplicació.

I així es fa servir la selecció dinàmica, aprofitant el ?? d'Operadors Bàsics:

function formatarCamp(camp, valor) {
  const formatador = formatadors[camp];
  if (!formatador) return String(valor);   // camp sense formatador: valor cru
  return formatador(valor);
}

const camps = ['estat', 'prioritat', 'data', 'hores'];
const valors = ['pendent', 'alta', '2026-09-05', 5];

for (let i = 0; i < camps.length; i++) {
  console.log(`${camps[i]}: ${formatarCamp(camps[i], valors[i])}`);
}
// estat: Pendent
// prioritat: 🔴 Alta
// data: 5 set 2026
// hores: 5 h

El const [any, mes, dia] = [...] del formatador de dates és desestructuració d'arrays; s'estudia a Desestructuració d'Arrays. Aquí només significa "assigna el primer element a any, el segon a mes i el tercer a dia".

  1. Una taula de validadors recorrible

El segon patró que desbloquegen les funcions com a valors és una llista de regles. Al Mòdul 2, validar una tasca era un bloc de quaranta línies amb if encadenats. Ara cada regla és una entrada d'un array, amb el seu codi i el seu missatge:

const validadors = [
  {
    regla: 'R2',
    missatge: 'El títol és obligatori.',
    comprovar: (titol, hores, prioritat, dataLimit) => titol.trim().length > 0
  },
  {
    regla: 'R3',
    missatge: 'Les hores han de ser entre 0 i 40.',
    comprovar: (titol, hores, prioritat, dataLimit) => hores > 0 && hores <= 40
  },
  {
    regla: 'R6',
    missatge: 'La prioritat ha de ser alta, mitjana o baixa.',
    comprovar: (titol, hores, prioritat, dataLimit) =>
      prioritat === 'alta' || prioritat === 'mitjana' || prioritat === 'baixa'
  },
  {
    regla: 'R4',
    missatge: 'La data límit no pot ser anterior a avui.',
    comprovar: (titol, hores, prioritat, dataLimit) => dataLimit >= AVUI
  }
];

function validarTasca(titol, hores, prioritat, dataLimit) {
  const errors = [];

  for (let i = 0; i < validadors.length; i++) {
    const v = validadors[i];
    if (!v.comprovar(titol, hores, prioritat, dataLimit)) {
      errors.push(`${v.regla}: ${v.missatge}`);
    }
  }

  return errors;
}

console.log(validarTasca('Pressupost de la fusteria', 5, 'alta', '2026-09-05'));
// [ 'R4: La data límit no pot ser anterior a avui.' ]

console.log(validarTasca('   ', 60, 'urgent', '2026-10-01'));
// [ 'R2: El títol és obligatori.',
//   'R3: Les hores han de ser entre 0 i 40.',
//   'R6: La prioritat ha de ser alta, mitjana o baixa.' ]

Llegeix bé el que ha passat aquí: afegir una regla nova ja no vol dir tocar validarTasca, sinó afegir un objecte a l'array. La funció que valida no sap quantes regles hi ha ni què comproven; només sap recórrer-les i cridar-les. Aquesta separació entre el motor i les regles és una de les idees més rendibles de la programació, i a Funcions d'Ordre Superior la portaràs molt més enllà.

  1. IIFE: la funció que es crida a si mateixa en néixer

Una IIFE (Immediately Invoked Function Expression, expressió de funció invocada immediatament) és una funció que es defineix i s'executa a l'acte:

(function () {
  const clau = 'valor privat';
  console.log('Inicialitzant Nómada Tasques…');
})();

// Versió amb fletxa
(() => {
  console.log('Igual, però més curt.');
})();

Els parèntesis exteriors converteixen la declaració en una expressió; els () finals la criden. Es feien servir massivament abans del 2015 per un motiu molt concret: crear un àmbit privat. Abans de let i const, qualsevol var del fitxer es tornava global i podia col·lidir amb un altre script de la pàgina. Embolcallar-ho tot en una IIFE aïllava les variables.

// El patró clàssic dels anys de jQuery
var NomadaTasques = (function () {
  var comptador = 0;                // invisible des de fora
  return {
    seguentId: function () { return ++comptador; }
  };
})();

console.log(NomadaTasques.seguentId());   // 1
console.log(NomadaTasques.seguentId());   // 2
console.log(typeof comptador);            // 'undefined' → està protegit

Encara cal? Gairebé mai. Avui tens dues eines millors:

Necessitat Solució antiga Solució moderna
Aïllar variables d'un fitxer IIFE Mòduls ES (05-04)
Aïllar variables d'un bloc IIFE Un bloc { } amb let/const
Estat privat en una funció IIFE Closures (03-04)

Convé reconèixer el patró perquè apareix en moltíssim codi heretat, però en codi nou el normal és no escriure'l.

  1. Quan triar cada forma

A la pràctica professional, l'elecció es redueix a aquestes pautes:

Situació Forma recomanada Motiu
Funció principal d'un fitxer (validarTasca, crearTasca) Declaració o const + expressió Nom clar a les traces; totes dues valen, tria un estil i sigues coherent
Callback curt d'una línia Fletxa amb retorn implícit Màxima brevetat i llegibilitat
Funció desada en un objecte de configuració Fletxa És un valor entre altres valors
Mètode d'un objecte que fa servir les dades de l'objecte function (o sintaxi de mètode) Necessita el seu propi this (vegeu 04-02)
Funció recursiva Declaració El nom està garantit dins del cos
Gestor d'esdeveniment del DOM que fa servir l'element Depèn Al Mòdul 6 en veuràs els dos casos

I una recomanació d'estil que segueixen la majoria d'equips: fes servir const + fletxa per defecte, i declaració només quan vulguis destacar una funció principal del fitxer. L'important no és quina tries, sinó que el fitxer sencer sigui coherent.

Errors Habituals i Consells

1. Cridar una expressió abans de definir-la.

console.log(formatar('alta'));                   // ✗ ReferenceError
const formatar = (p) => p.toUpperCase();

Amb expressions i fletxes: defineix a dalt, fes-ho servir a baix. Sempre.

2. Oblidar el return en fer servir claus en una fletxa.

const doble = (n) => { n * 2; };          // ✗ retorna undefined
const doble = (n) => { return n * 2; };   // ✓
const doble = (n) => n * 2;               // ✓ encara millor

3. Retornar un objecte sense parèntesis. Ja ho has vist a l'apartat 5: (x) => ({ ... }).

4. Oblidar el punt i coma després d'una expressió de funció. No sol trencar res gràcies a l'ASI, però pot produir errors molt estranys si la línia següent comença per ( o [.

5. Fer servir una fletxa com a mètode que necessita this. El símptoma és un undefined inexplicable en llegir una propietat de l'objecte. Si et passa al Mòdul 4, torna a l'apartat 7.

6. Confondre funcio amb funcio() en desar-la.

const formatadors = { estat: etiquetaEstat() };   // ✗ desa el RESULTAT
const formatadors = { estat: etiquetaEstat };     // ✓ desa la FUNCIÓ

Aquest error és especialment difícil de veure perquè no dóna error de sintaxi: simplement desa undefined o un text on esperaves una funció, i l'errada apareix línies després amb un TypeError: ... is not a function.

7. Consell: si la fletxa ocupa més de dues línies, posa-li claus. El retorn implícit amb expressions llarguíssimes i operadors ternaris encadenats és difícil de llegir i pitjor de depurar (no pots posar un console.log intermedi sense reescriure-la).

8. Consell: dóna nom a les funcions encara que siguin anònimes. Assignar-les a una const amb nom descriptiu no és només estil: és el que fa llegibles els missatges d'error del Mòdul 8.

Exercicis

Exercici 1 — De declaracions a fletxes

Reescriu aquestes tres funcions com a fletxes, fent servir la forma més breu possible en cada cas, i comprova que donen el mateix resultat.

function esFeta(estat) {
  return estat === 'feta';
}

function esforc(prioritat, hores) {
  return pesDePrioritat(prioritat) * hores;
}

function resumCurt(titol, responsable, hores) {
  const nom = responsable === null ? 'sense assignar' : responsable;
  return `${titol} (${nom}, ${hores} h)`;
}

Exercici 2 — Taula de comparadors

Crea un objecte comparadors les claus del qual siguin 'perHores', 'perData' i 'perPrioritat', i els valors del qual siguin funcions que rebin les dades de dues tasques (per índex) i retornin -1, 0 o 1 segons quina ha d'anar abans. Després escriu elMesUrgent(criteri, ...) que recorri el backlog amb un bucle i retorni l'índex de la tasca que queda primera segons el criteri triat. No facis servir sort (arriba a 04-05).

Exercici 3 — Detectar l'errada

Cadascun d'aquests fragments té un error relacionat amb el que s'ha estudiat a la lliçó. Identifica'l i corregeix-lo.

// a)
const etiqueta = (estat) => { estat.toUpperCase() };
console.log(etiqueta('feta'));

// b)
const novaTasca = (titol, hores) => { titol: titol, hores: hores };
console.log(novaTasca('Cartelleria', 6));

// c)
console.log(pesDe('alta'));
const pesDe = (p) => (p === 'alta' ? 3 : 1);

// d)
const accions = { imprimir: console.log('Hola') };
accions.imprimir('Adeu');

Solucions

Exercici 1

'use strict';

const pesDePrioritat = (prioritat) => {
  if (prioritat === 'alta') return 3;
  if (prioritat === 'mitjana') return 2;
  if (prioritat === 'baixa') return 1;
  return 0;
};

// Un paràmetre, una expressió → forma mínima
const esFeta = (estat) => estat === 'feta';

// Dos paràmetres, una expressió → retorn implícit
const esforc = (prioritat, hores) => pesDePrioritat(prioritat) * hores;

// Necessita una variable intermèdia → cos de bloc
const resumCurt = (titol, responsable, hores) => {
  const nom = responsable ?? 'sense assignar';
  return `${titol} (${nom}, ${hores} h)`;
};

console.log(esFeta('feta'));                                     // true
console.log(esforc('alta', 12));                                 // 36
console.log(resumCurt('Actualitzar el web de reserves', null, 14));
// Actualitzar el web de reserves (sense assignar, 14 h)

Comentari: la tercera no s'hauria d'escriure amb retorn implícit. Cabria en una línia fent servir ??, però el bloc deixa clar que hi ha dos passos i permet afegir un console.log de depuració sense reescriure res. Observa a més que responsable ?? 'sense assignar' substitueix el ternari: el ?? d'Operadors Bàsics cobreix null i undefined, que és exactament el cas de la R8.

Exercici 2

const ids         = [1, 2, 3, 4, 5, 6];
const prioritats  = ['alta', 'mitjana', 'alta', 'baixa', 'mitjana', 'alta'];
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'];

const comparadors = {
  // Més hores primer
  perHores: (a, b) => {
    if (hores[a] > hores[b]) return -1;
    if (hores[a] < hores[b]) return 1;
    return 0;
  },

  // Data més propera primer (les cadenes ISO es comparen directament)
  perData: (a, b) => {
    if (datesLimit[a] < datesLimit[b]) return -1;
    if (datesLimit[a] > datesLimit[b]) return 1;
    return 0;
  },

  // Més pes de prioritat primer
  perPrioritat: (a, b) => {
    const pa = pesDePrioritat(prioritats[a]);
    const pb = pesDePrioritat(prioritats[b]);
    if (pa > pb) return -1;
    if (pa < pb) return 1;
    return 0;
  }
};

function elMesUrgent(criteri) {
  const comparar = comparadors[criteri];
  if (!comparar) throw new Error(`Criteri desconegut: ${criteri}`);

  let millor = 0;
  for (let i = 1; i < ids.length; i++) {
    if (comparar(i, millor) < 0) millor = i;
  }
  return millor;
}

console.log(ids[elMesUrgent('perHores')]);      // 3  (14 h)
console.log(ids[elMesUrgent('perData')]);       // 6  (2026-09-05)
console.log(ids[elMesUrgent('perPrioritat')]);  // 1  (primera 'alta' trobada)

Comentari: el patró "màxim amb bandera" és el mateix de Bucles, però ara el criteri de comparació hi entra com a dada. Canviar l'ordre del backlog ja no requereix reescriure el bucle. El throw per al criteri desconegut aplica el principi de fallar aviat de Gestió d'Errors.

Exercici 3

Fragment Error Correcció
a) Claus sense return → retorna undefined const etiqueta = (estat) => estat.toUpperCase();
b) Objecte literal sense parèntesis → les claus són un bloc const novaTasca = (titol, hores) => ({ titol, hores });
c) Expressió feta servir abans de definir-la → ReferenceError Moure la definició abans de la crida
d) Es desa el resultat de console.log('Hola') (undefined), no la funció const accions = { imprimir: console.log };

A b) apareix l'abreviatura { titol, hores }, equivalent a { titol: titol, hores: hores }; s'estudia a Introducció als Objectes. A d), el símptoma real és un TypeError: accions.imprimir is not a function a la línia següent, lluny de l'error veritable: un recordatori que el punt on peta i el punt on és l'errada rarament coincideixen.

Conclusió

Has après que en JavaScript una funció és un valor de primera classe: la pots assignar a una variable, desar-la en un array o en un objecte, comparar-la per referència i passar-la com a argument. Aquesta propietat, que sembla un detall tècnic, és la que fa possibles els dos patrons que ja has posat en marxa a Nómada Tasques: l'objecte formatadors, que centralitza tota la presentació de camps i permet triar el formatador amb una variable, i l'array validadors, que converteix cada regla de negoci en una dada i deixa validarTasca completament aliena a quantes regles existeixin.

Coneixes les tres maneres d'escriure una funció i les seves diferències reals: la declaració, disponible abans de la seva línia; l'expressió de funció, anònima o amb nom intern, que només existeix a partir de la seva assignació; i la funció fletxa, amb les seves variants de cos de bloc, retorn implícit, un paràmetre i sense paràmetres, a més del truc dels parèntesis per retornar un objecte literal. Saps que la fletxa no té this propi ni arguments ni es pot fer servir amb new, i que aquest primer punt el tancaràs a Mètodes d'Objecte i this. I reconeixes la IIFE, el patró amb què s'aïllaven variables abans que existissin let, const i els mòduls.

Hi ha una cosa que s'ha anat tornant incòmoda pel camí. Els validadors de l'apartat 9 reben quatre paràmetres encara que cadascun en faci servir només un; descriureTasca de la lliçó anterior en rebia vuit; i encara no saps què passa si algú crida una funció amb menys arguments dels declarats, ni com donar un valor per defecte a revisor quan no s'indica. Tot això —com hi entren les dades i com en surten els resultats— és el tema de Paràmetres i Valors de Retorn, on construiràs crearTasca() amb valors per defecte i resumirCarrega() retornant diversos totals d'una sola vegada.

Curs de JavaScript: De Principiant a Avançat

Mòdul 1: Introducció a JavaScript

Mòdul 2: Estructures de Control

Mòdul 3: Funcions

Mòdul 4: Objectes i Arrays

Mòdul 5: Objectes i Funcions Avançades

Mòdul 6: El Model d'Objectes del Document (DOM)

Mòdul 7: APIs del Navegador i Temes Avançats

Mòdul 8: Proves i Depuració

Mòdul 9: Rendiment i Optimització

Mòdul 10: Frameworks i Llibreries de JavaScript

Mòdul 11: Projecte Final

© Copyright 2026. Tots els drets reservats