Al final de la lliçó anterior va quedar una pregunta a l'aire: si un objecte pot guardar números, strings i arrays, per què no funcions? La resposta és que sí que pot, i això canvia la manera d'organitzar el codi. Una funció desada en una propietat s'anomena mètode, i permet que el tauler de Taller Nómada no sigui només una bossa de tasques, sinó un objecte que sap afegir una tasca, canviar-li l'estat i calcular el seu propi resum. Amb els mètodes apareix this, la paraula clau amb pitjor fama de JavaScript: no perquè sigui complicada, sinó perquè gairebé tothom l'aprèn amb la regla equivocada. En aquesta lliçó l'aprendràs amb la regla correcta —this depèn de com es crida la funció, no d'on es defineix—, veuràs les quatre formes d'invocació en una taula, resoldràs el problema clàssic de perdre this en passar un mètode com a callback i tancaràs per fi el deute que va deixar 03-02 sobre les funcions fletxa.

Contingut

  1. De funció solta a mètode
  2. La sintaxi abreujada de mètodes
  3. Què és this i la regla fonamental
  4. Les quatre formes d'invocació
  5. call, apply i bind
  6. L'objecte tauler de Taller Nómada
  7. El problema clàssic: perdre this en un callback
  8. Les tres solucions
  9. Per què la funció fletxa no té this propi
  10. this en bucles i funcions imbricades
  11. Quan la fletxa ajuda i quan fa nosa
  12. Errors Habituals i Consells
  13. Exercicis
  14. Conclusió

  1. De funció solta a mètode

Partim del backlog de la lliçó anterior i de descriureTasca(tasca, avui). Ara mateix, la funció i les dades viuen separades:

const tasca = backlog[0];
console.log(descriureTasca(tasca, AVUI));

Res no impedeix ficar la funció dins de l'objecte:

const tasca = {
  id: 6,
  titol: 'Pressupost de la fusteria',
  responsable: 'Iván',
  prioritat: 'alta',
  estat: 'pendent',
  horesEstimades: 5,
  dataLimit: '2026-09-05',

  // Una propietat el valor de la qual és una funció: això és un MÈTODE
  descriure: function (avui) {
    return `[${this.id}] ${this.titol} · ${this.responsable} · ${this.horesEstimades} h`;
  }
};

console.log(tasca.descriure('2026-09-20'));
// [6] Pressupost de la fusteria · Iván · 5 h

Dues coses noves en aquest bloc:

  • descriure és una propietat com qualsevol altra; l'única cosa especial és que el seu valor és una funció. Ho pots comprovar: typeof tasca.descriure és 'function', i Object.keys(tasca) la inclou.
  • Dins del mètode apareix this, que en aquesta crida es refereix al mateix objecte tasca. Gràcies a ell, el mètode pot llegir les dades del «seu» objecte sense que li passis com a argument.

La diferència de vocabulari és simple:

Terme Definició Exemple
Funció Codi amb nom que s'invoca per si mateix pesDePrioritat('alta')
Mètode Funció desada en una propietat d'un objecte tasca.descriure('2026-09-20')
Receptor L'objecte que hi ha a l'esquerra del punt a la crida tasca

  1. La sintaxi abreujada de mètodes

Escriure descriure: function (avui) { ... } funciona, però des d'ES2015 existeix una forma més curta i és la que es fa servir avui:

const tauler = {
  nom: 'Taller Nómada',

  // Sintaxi llarga (encara vàlida)
  saludarLlarg: function () {
    return `Panell de ${this.nom}`;
  },

  // Sintaxi abreujada: es treuen els dos punts i la paraula function
  saludar() {
    return `Panell de ${this.nom}`;
  }
};

console.log(tauler.saludar());        // 'Panell de Taller Nómada'
console.log(tauler.saludarLlarg());   // 'Panell de Taller Nómada'

Totes dues fan el mateix. L'abreujada és més curta, més llegible i és la que has de fer servir. Compte amb una tercera opció que sembla equivalent però no ho és:

const taulerTrencat = {
  nom: 'Taller Nómada',
  saludar: () => `Panell de ${this.nom}`     // ✗ funció fletxa
};

console.log(taulerTrencat.saludar());    // 'Panell de undefined'

Aquest undefined és el tema de l'apartat 9. De moment, queda't amb la regla operativa: per als mètodes d'un objecte literal, fes servir sempre la sintaxi abreujada, mai una fletxa.

  1. Què és this i la regla fonamental

this és una paraula clau que, dins d'una funció, apunta a un objecte. Quin és aquest objecte es decideix en el moment de la crida, no en el moment d'escriure la funció. Aquesta és la regla que cal memoritzar:

this no depèn d'on es defineix la funció, sinó de COM se la crida.

Sona abstracte fins que veus una mateixa funció comportar-se de tres maneres diferents:

'use strict';

function quiSoc() {
  return this;
}

const objecteA = { nom: 'A', quiSoc };
const objecteB = { nom: 'B', quiSoc };

console.log(objecteA.quiSoc().nom);   // 'A'
console.log(objecteB.quiSoc().nom);   // 'B'
console.log(quiSoc());                // undefined  (en mode estricte)

És la mateixa funció, definida una sola vegada. L'única cosa que canvia és el que hi ha a l'esquerra del punt en cridar-la. Amb aquesta imatge mental, this deixa de ser màgia: és simplement «l'objecte sobre el qual s'ha invocat això».

flowchart LR
    A["objecteA.quiSoc()"] --> B["this = objecteA"]
    C["objecteB.quiSoc()"] --> D["this = objecteB"]
    E["quiSoc()"] --> F["this = undefined<br/>(mode estricte)"]
    G["quiSoc.call(objecteA)"] --> H["this = objecteA"]

  1. Les quatre formes d'invocació

Tota la complexitat de this es redueix a aquesta taula. Quan dubtis d'a què apunta this, busca en quina fila ets.

Forma d'invocació Com s'escriu Valor de this
Crida simple funcio() undefined en mode estricte; l'objecte global (window/globalThis) sense mode estricte
Com a mètode objecte.metode() L'objecte receptor (el que hi ha a l'esquerra del punt)
Amb new new Constructor() L'objecte nou que es crea
Amb call/apply/bind funcio.call(obj, ...) L'objecte que tu indiques explícitament

Anem una per una.

Crida simple. És el que has fet durant tot el Mòdul 3. En mode estricte ('use strict', que fas servir des de 01-04) this és undefined. Sense mode estricte seria l'objecte global, i aquest comportament silenciós és una font inesgotable de bugs: per això existeix el mode estricte.

'use strict';

function informar() {
  console.log(this);
}

informar();          // undefined

Com a mètode. El cas normal: this és el receptor.

const equip = {
  coordinadora: 'Marta',
  presentar() {
    return `Coordina ${this.coordinadora}`;
  }
};

console.log(equip.presentar());   // 'Coordina Marta'

Aquí convé un advertiment: this és l'objecte que hi ha immediatament a l'esquerra del punt en la crida, no l'objecte on el mètode està escrit. Si mous el mètode a una altra variable, canvia tot (apartat 7).

Amb new. Quan crides una funció amb new, JavaScript crea un objecte buit, fa que this apunti a ell, executa el cos i retorna aquest objecte.

function Tasca(id, titol) {
  this.id = id;
  this.titol = titol;
  this.estat = 'pendent';
}

const nova = new Tasca(7, 'Revisar la guillotina');
console.log(nova);   // Tasca { id: 7, titol: 'Revisar la guillotina', estat: 'pendent' }

Aquest és el mecanisme sobre el qual es construeixen els constructors, els prototips i les classes, i s'estudia a fons a Prototips i Herència i Classes i POO. Aquí només necessites saber que existeix i que és la tercera fila de la taula.

Amb call, apply o bind. És l'apartat següent.

  1. call, apply i bind

Tota funció de JavaScript porta de sèrie tres mètodes que serveixen per decidir this a mà.

function descriure(prefix, sufix) {
  return `${prefix}${this.titol} (${this.horesEstimades} h)${sufix}`;
}

const tasca3 = { titol: 'Actualitzar el web de reserves', horesEstimades: 14 };

// call: this primer, després els arguments SOLTS
console.log(descriure.call(tasca3, '» ', ' ⏳'));
// » Actualitzar el web de reserves (14 h) ⏳

// apply: this primer, després els arguments en un ARRAY
console.log(descriure.apply(tasca3, ['» ', ' ⏳']));
// » Actualitzar el web de reserves (14 h) ⏳

// bind: NO crida; retorna una funció NOVA amb this fixat per sempre
const descriureTasca3 = descriure.bind(tasca3);
console.log(descriureTasca3('· ', ''));
// · Actualitzar el web de reserves (14 h)

Resum comparatiu:

Mètode Executa ja? Com passa els arguments Què retorna
call(this, a, b) Solts El resultat de la funció
apply(this, [a, b]) En un array El resultat de la funció
bind(this, a) No Solts (es poden prefixar) Una funció nova amb this lligat

Un truc mnemotècnic: call = comes, apply = array, bind = bloqueja (fixa this i retorna una funció per a més tard). A la pràctica moderna call i apply es fan servir poc —el spread de 04-07 substitueix gairebé tots els usos d'apply—, però bind continua sent essencial, com veuràs a l'apartat 8.

Un detall que sorprèn: bind és definitiu. Una funció ja lligada no es pot tornar a lligar.

const lligadaAMarta = descriure.bind({ titol: 'A', horesEstimades: 1 });
const intent = lligadaAMarta.bind({ titol: 'B', horesEstimades: 2 });
console.log(intent('', ''));   // 'A (1 h)'  ← el segon bind no té efecte

  1. L'objecte tauler de Taller Nómada

Amb això ja podem construir la peça central de la lliçó: un objecte que guarda el backlog i les operacions sobre ell. La Marta ho descriuria així: «el tauler és la llista de tasques més el que s'hi pot fer».

'use strict';

const AVUI = '2026-09-20';
const PESOS = { alta: 3, mitjana: 2, baixa: 1 };
const MARQUES = { feta: '✓', 'en-curs': '▸', pendent: '○' };
const ESTATS_VALIDS = ['pendent', 'en-curs', 'feta'];

const tauler = {
  nom: 'Taller Nómada',
  avui: AVUI,
  tasques: [
    { id: 1, titol: 'Redissenyar la sala polivalent',           responsable: 'Iván',  prioritat: 'alta',    estat: 'en-curs', horesEstimades: 12, dataLimit: '2026-09-30' },
    { id: 2, titol: 'Cartelleria del taller de serigrafia',     responsable: 'Marta', prioritat: 'mitjana', estat: 'pendent', horesEstimades: 6,  dataLimit: '2026-10-15' },
    { id: 3, titol: 'Actualitzar el web de reserves',           responsable: 'Lucía', prioritat: 'alta',    estat: 'pendent', horesEstimades: 14, dataLimit: '2026-10-02' },
    { id: 4, titol: 'Inventari de tintes de serigrafia',        responsable: 'Marta', prioritat: 'baixa',   estat: 'feta',    horesEstimades: 3,  dataLimit: '2026-09-12' },
    { id: 5, titol: 'Guia sobre enquadernació per a residents', responsable: 'Iván',  prioritat: 'mitjana', estat: 'en-curs', horesEstimades: 8,  dataLimit: '2026-11-05' },
    { id: 6, titol: 'Pressupost de la fusteria',                responsable: 'Iván',  prioritat: 'alta',    estat: 'pendent', horesEstimades: 5,  dataLimit: '2026-09-05' }
  ],

  // ─── Mètodes de consulta ────────────────────────────────────────
  cercarPerId(id) {
    for (const tasca of this.tasques) {
      if (tasca.id === id) return tasca;
    }
    return null;
  },

  // ─── Mètodes que modifiquen el tauler ───────────────────────────
  afegir(tasca) {
    if (this.cercarPerId(tasca.id) !== null) {
      throw new Error(`Ja existeix una tasca amb id ${tasca.id}.`);
    }
    this.tasques.push(tasca);
    return this;             // retornar this permet encadenar crides
  },

  canviarEstat(id, estatNou) {
    if (!ESTATS_VALIDS.includes(estatNou)) {
      throw new Error(`Estat no vàlid: ${estatNou}`);
    }
    const tasca = this.cercarPerId(id);
    if (tasca === null) {
      throw new Error(`No hi ha cap tasca amb id ${id}.`);
    }
    tasca.estat = estatNou;
    return this;
  },

  // ─── Mètode d'agregació ─────────────────────────────────────────
  resum() {
    let obertes = 0;
    let horesObertes = 0;
    let vencudes = 0;
    let esforc = 0;

    for (const tasca of this.tasques) {
      esforc += (PESOS[tasca.prioritat] ?? 0) * tasca.horesEstimades;
      if (tasca.estat === 'feta') continue;
      obertes++;
      horesObertes += tasca.horesEstimades;
      if (tasca.dataLimit < this.avui) vencudes++;
    }

    return { total: this.tasques.length, obertes, horesObertes, vencudes, esforc };
  },

  linia(tasca) {
    const marca = MARQUES[tasca.estat] ?? '?';
    const avis = tasca.dataLimit < this.avui && tasca.estat !== 'feta' ? ' ⚠ VENÇUDA' : '';
    return `${marca} [${tasca.id}] ${tasca.titol} · ${tasca.responsable} · ${tasca.horesEstimades} h${avis}`;
  }
};

console.log(tauler.resum());
// { total: 6, obertes: 5, horesObertes: 45, vencudes: 1, esforc: 124 }

console.log(tauler.linia(tauler.cercarPerId(6)));
// ○ [6] Pressupost de la fusteria · Iván · 5 h ⚠ VENÇUDA

Els números coincideixen amb el backlog canònic: 6 tasques, 5 obertes, 45 h obertes, 1 vençuda i un esforç ponderat de 124. Repassa tres decisions de disseny d'aquest objecte:

  1. this.tasques, no tasques. Dins d'un mètode, per arribar a les propietats del mateix objecte cal passar per this. Escriure tasques.push(...) donaria ReferenceError, perquè no existeix cap variable amb aquest nom.
  2. Els mètodes es criden entre si amb this. afegir fa servir this.cercarPerId(...). Això és el que permet reaprofitar lògica sense duplicar-la.
  3. afegir i canviarEstat retornen this. És el patró d'interfície fluida: com que cada crida retorna el mateix tauler, es poden encadenar.
tauler
  .afegir({ id: 7, titol: 'Revisar la guillotina per enquadernar', responsable: 'Lucía',
            prioritat: 'mitjana', estat: 'pendent', horesEstimades: 2, dataLimit: '2026-10-20' })
  .canviarEstat(2, 'en-curs')
  .canviarEstat(6, 'feta');

console.log(tauler.resum());
// { total: 7, obertes: 5, horesObertes: 42, vencudes: 0, esforc: 128 }

I els errors fan servir el throw new Error que vas aprendre a 02-05, de manera que qui cridi pot embolcallar-ho en un try/catch:

try {
  tauler.canviarEstat(99, 'feta');
} catch (error) {
  console.log(`No s'ha pogut actualitzar: ${error.message}`);
}
// No s'ha pogut actualitzar: No hi ha cap tasca amb id 99.

  1. El problema clàssic: perdre this en un callback

Aquí arriba el moment en què this mossega. Recupera la regla: this depèn de com es crida la funció. Si extreus un mètode del seu objecte, la crida deixa de tenir receptor.

'use strict';

const resumir = tauler.resum;     // extraiem el mètode a una variable
console.log(resumir());
// ✗ TypeError: Cannot read properties of undefined (reading 'tasques')

Per què? Perquè resumir() és una crida simple (primera fila de la taula): this val undefined, i this.tasques peta. La funció és la mateixa; la crida, no.

El cas realment freqüent és més subtil, perquè no sembla que estiguis extraient res: passa en passar un mètode com a callback, cosa que faràs constantment amb els esdeveniments del Mòdul 6 i amb els mètodes d'array de la resta d'aquest mòdul.

const notificador = {
  destinatari: 'Marta',
  avisar(titol) {
    console.log(`Avís per a ${this.destinatari}: ${titol}`);
  }
};

notificador.avisar('Pressupost de la fusteria');
// Avís per a Marta: Pressupost de la fusteria   ✓

const titols = ['Pressupost de la fusteria', 'Actualitzar el web de reserves'];

titols.forEach(notificador.avisar);
// ✗ TypeError: Cannot read properties of undefined (reading 'destinatari')

El que passa és que titols.forEach(notificador.avisar) no passa el mètode, passa la funció que hi havia a dins. Quan forEach la invoca, ho fa com a crida simple, sense cap receptor:

flowchart TD
    A["notificador.avisar('x')"] --> B["Crida AMB receptor<br/>this = notificador ✓"]
    C["const f = notificador.avisar<br/>f('x')"] --> D["Crida SENSE receptor<br/>this = undefined ✗"]
    E["forEach(notificador.avisar)"] --> D

La imatge mental correcta: el punt no forma part de la funció. notificador.avisar significa «dóna'm el valor desat a la propietat avisar». Aquest valor és una funció anònima que no recorda d'on va sortir. El vincle amb notificador només existeix durant la crida amb punt.

  1. Les tres solucions

Hi ha tres maneres d'arreglar-ho, i convé conèixer-les totes tres perquè te les trobaràs en codi d'altri.

Solució 1: bind. Lligues el mètode al seu objecte i passes la funció lligada.

titols.forEach(notificador.avisar.bind(notificador));
// Avís per a Marta: Pressupost de la fusteria
// Avís per a Marta: Actualitzar el web de reserves

Solució 2: una funció fletxa embolcallant. Crides el mètode amb punt dins de la fletxa, de manera que la crida sí que té receptor.

titols.forEach((titol) => notificador.avisar(titol));

Aquesta és la més llegible i la que es veu més sovint avui. Fixa't que la clau no és la fletxa en si, sinó que la invocació conserva el punt: notificador.avisar(titol).

Solució 3: un mètode fletxa com a camp de l'objecte. Es defineix la propietat amb una fletxa que captura this de l'àmbit del voltant.

function crearNotificador(destinatari) {
  const obj = {
    destinatari,
    avisar: (titol) => console.log(`Avís per a ${obj.destinatari}: ${titol}`)
  };
  return obj;
}

const avis = crearNotificador('Lucía');
titols.forEach(avis.avisar);
// Avís per a Lucía: Pressupost de la fusteria
// Avís per a Lucía: Actualitzar el web de reserves

Aquesta tercera variant és la menys habitual amb objectes literals (funciona millor amb classes, Mòdul 5), però il·lustra el patró que veuràs en molts projectes. Comparació:

Solució Avantatges Inconvenients
bind Explícita; funciona amb qualsevol funció Verbosa; crea una funció nova cada vegada que s'executa
Fletxa embolcallant Curta, clara, permet reordenar arguments Un nivell més d'imbricació
Mètode fletxa El mètode «mai no es deslliga» Cada objecte té la seva pròpia còpia de la funció; no es pot reaprofitar amb call

I hi ha una quarta via específica d'alguns mètodes d'array: forEach, map, filter i some accepten un segon argument amb el this que vols fer servir dins del callback.

const tasquesCurtes = ['Demanar pressupostos', 'Visitar dos proveïdors'];
tasquesCurtes.forEach(notificador.avisar, notificador);
// Avís per a Marta: Demanar pressupostos
// Avís per a Marta: Visitar dos proveïdors

Funciona, però es fa servir poc perquè és fàcil de passar per alt en llegir el codi.

  1. Per què la funció fletxa no té this propi

A 03-02 vam dir que les funcions fletxa es comporten de manera diferent amb this i vam deixar l'explicació per a més endavant. Ha arribat el moment.

Una funció fletxa no té el seu propi this. Dins d'una fletxa, this és exactament el mateix que hi havia a l'àmbit on la fletxa va ser escrita. Es resol com qualsevol altra variable, seguint la cadena d'àmbits que vas estudiar a 03-04.

Això explica la fallada de l'apartat 2:

'use strict';

const taulerTrencat = {
  nom: 'Taller Nómada',
  saludar: () => `Panell de ${this.nom}`
};

console.log(taulerTrencat.saludar());   // 'Panell de undefined'

La fletxa es va escriure fora de qualsevol funció, a l'àmbit de mòdul. Allà this no és l'objecte que la conté (un literal d'objecte no crea àmbit), sinó el que hi hagués en aquell nivell: undefined en un mòdul, o module.exports a Node, o l'objecte global en un script clàssic. En cap d'aquests casos hi ha una propietat nom.

La taula que resumeix la diferència:

Funció normal (function, o mètode abreujat) Funció fletxa
this Es decideix a la crida (les quatre formes) S'hereta de l'àmbit on es va escriure
Hi afecta call/apply/bind? No: s'ignoren
Serveix com a mètode d'objecte literal? No
Serveix com a callback que necessita el this de fora? No sense bind Sí, perfectament
arguments? No (fes servir ...rest, 03-03)
Es pot fer servir amb new? No

Comprova-ho:

const objecte = { valor: 42 };

const normal = function () { return this?.valor; };
const fletxa = () => this?.valor;

console.log(normal.call(objecte));   // 42        ← call funciona
console.log(fletxa.call(objecte));   // undefined ← call s'ignora

  1. this en bucles i funcions imbricades

El cas que més confon els principiants: una funció normal imbricada dins d'un mètode. Com que és una crida simple, perd el this del mètode.

'use strict';

const informe = {
  nom: 'Taller Nómada',
  tasques: [{ titol: 'Pressupost de la fusteria' }, { titol: 'Actualitzar el web de reserves' }],

  imprimirMalament() {
    this.tasques.forEach(function (tasca) {
      console.log(`${this.nom}: ${tasca.titol}`);   // ✗ this és undefined
    });
  }
};

// informe.imprimirMalament();
// ✗ TypeError: Cannot read properties of undefined (reading 'nom')

imprimirMalament sí que té bé el seu this (s'ha cridat amb punt). Però la funció anònima que rep forEach s'invoca sense receptor, i el seu this no té res a veure amb el del mètode que l'envolta. Abans de les fletxes, això es resolia amb un truc que veuràs en codi antic:

imprimirAmbSelf() {
  const self = this;                    // es desa el this bo en una variable normal
  this.tasques.forEach(function (tasca) {
    console.log(`${self.nom}: ${tasca.titol}`);
  });
}

Amb una fletxa, el truc ja no cal, perquè la fletxa hereta el this del mètode on es va escriure:

const informe = {
  nom: 'Taller Nómada',
  tasques: [{ titol: 'Pressupost de la fusteria' }, { titol: 'Actualitzar el web de reserves' }],

  imprimir() {
    this.tasques.forEach((tasca) => {
      console.log(`${this.nom}: ${tasca.titol}`);   // ✓ this = informe
    });
  }
};

informe.imprimir();
// Taller Nómada: Pressupost de la fusteria
// Taller Nómada: Actualitzar el web de reserves

Un for...of clàssic no té aquest problema en absolut, perquè no introdueix cap funció nova:

imprimirAmbFor() {
  for (const tasca of this.tasques) {
    console.log(`${this.nom}: ${tasca.titol}`);   // ✓ mateix this del mètode
  }
}

Regla derivada, molt pràctica: un bucle no canvia this; una funció sí. Si dins d'un mètode apareix la paraula function, sospita.

  1. Quan la fletxa ajuda i quan fa nosa

Amb tot l'anterior, la decisió és mecànica:

Situació Tria Motiu
Mètode d'un objecte literal Mètode abreujat metode() {} Necessita el receptor com a this
Callback dins d'un mètode Funció fletxa Hereta el this correcte sense bind
Callback que no fa servir this (map, filter, comparadors) Funció fletxa Més curta; this és irrellevant
Gestor d'esdeveniment que necessita l'element del DOM Funció normal El navegador posa l'element a this (Mòdul 6)
Constructor o funció que es farà servir amb new Funció normal Les fletxes no admeten new
Funció solta sense relació amb cap objecte Qualsevol this no hi participa

Aplicat al tauler, la versió definitiva combina totes dues: mètodes abreujats per fora, fletxes per dins.

const taulerFinal = {
  nom: 'Taller Nómada',
  avui: AVUI,
  tasques: tauler.tasques,

  titolsVencuts() {
    return this.tasques
      .filter((t) => t.dataLimit < this.avui && t.estat !== 'feta')   // fletxa: this = taulerFinal
      .map((t) => t.titol);
  }
};

console.log(taulerFinal.titolsVencuts());
// [ 'Pressupost de la fusteria' ]

(Els mètodes filter i map que hi apareixen s'estudien a les lliçons 04-04 i 04-05; aquí només interessen com a exemple de callbacks dins d'un mètode.)

Errors Habituals i Consells

1. Oblidar this. dins d'un mètode.

resum() {
  for (const t of tasques) { }       // ✗ ReferenceError: tasques is not defined
  for (const t of this.tasques) { }  // ✓
}

2. Fer servir una fletxa com a mètode d'un objecte literal. saludar: () => this.nom mai no veurà l'objecte. Fes servir saludar() { ... }.

3. Passar un mètode com a callback sense lligar-lo. array.forEach(obj.metode) perd this. Escriu array.forEach((x) => obj.metode(x)).

4. Creure que bind modifica la funció original. No: en retorna una de nova. obj.metode.bind(obj); en una línia solta no fa absolutament res; cal desar el resultat.

5. Cridar bind dins d'un bucle o d'un render. Cada bind crea una funció diferent. Al Mòdul 6 això vol dir gestors d'esdeveniment que no es poden treure amb removeEventListener perquè la referència ja no és la mateixa. Lliga una vegada i desa el resultat.

6. Confiar en this sense mode estricte. Sense 'use strict', una crida simple posa this a l'objecte global i les assignacions a this.alguna_cosa creen variables globals silenciosament. Aquest curs fa servir mode estricte des de 01-04 precisament perquè aquest error es converteixi en un TypeError visible.

Consell professional. Quan no sàpigues a què apunta this, no raonis: imprimeix-lo. Un console.log(this) a la primera línia del mètode resol el dubte en dos segons, i al Mòdul 8 aprendràs a inspeccionar-lo amb un punt d'interrupció sense tocar el codi.

Exercicis

Exercici 1 — Mètodes d'una tasca. Escriu un objecte tascaWeb amb les dades de la tasca 3 del backlog (id 3, «Actualitzar el web de reserves», Lucía, alta, pendent, 14 h, '2026-10-02') i afegeix-hi tres mètodes abreujats: esAlta() (retorna true si la prioritat és 'alta'), estaVencuda(avui) (aplica la R10) i etiqueta() (retorna un string '[3] Actualitzar el web de reserves — Lucía'). Prova'ls amb AVUI = '2026-09-20'.

Exercici 2 — Caçar el this perdut. Aquest codi falla. Explica per què i arregla'l de dues maneres diferents (una amb bind i una altra amb funció fletxa), sense canviar el mètode recordar.

'use strict';

const agenda = {
  responsable: 'Iván',
  recordar(titol) {
    console.log(`${this.responsable} ha de fer: ${titol}`);
  }
};

const pendents = ['Redissenyar la sala polivalent', 'Pressupost de la fusteria'];
pendents.forEach(agenda.recordar);

Exercici 3 — Comptador d'hores per persona. Amplia l'objecte tauler amb un mètode horesDe(persona) que retorni les hores obertes (estat diferent de 'feta') d'aquesta persona, i un mètode informePerPersona() que retorni un objecte amb una clau per responsable i les seves hores obertes. Fes servir this i els mètodes entre si. Comprova que tauler.horesDe('Iván') dóna 25 i que l'informe quadra amb les 45 h obertes totals.

Solucions

Exercici 1

'use strict';

const AVUI = '2026-09-20';

const tascaWeb = {
  id: 3,
  titol: 'Actualitzar el web de reserves',
  responsable: 'Lucía',
  prioritat: 'alta',
  estat: 'pendent',
  horesEstimades: 14,
  dataLimit: '2026-10-02',

  esAlta() {
    return this.prioritat === 'alta';
  },

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

  etiqueta() {
    return `[${this.id}] ${this.titol} — ${this.responsable}`;
  }
};

console.log(tascaWeb.esAlta());            // true
console.log(tascaWeb.estaVencuda(AVUI));   // false (venç el 2 d'octubre)
console.log(tascaWeb.etiqueta());          // '[3] Actualitzar el web de reserves — Lucía'

Fixa't que estaVencuda rep avui com a paràmetre en lloc de llegir-lo d'una constant global: és la mateixa decisió de disseny de 03-03, i serveix per poder provar la funció amb qualsevol data.

Exercici 2

La fallada és a pendents.forEach(agenda.recordar). Allà no es passa «el mètode d'agenda», es passa la funció que hi ha desada a la propietat recordar. Quan forEach la invoca ho fa sense receptor —una crida simple—, així que en mode estricte this val undefined i this.responsable llança un TypeError.

// Solució A: bind
pendents.forEach(agenda.recordar.bind(agenda));

// Solució B: fletxa embolcallant, que conserva el punt a la crida
pendents.forEach((titol) => agenda.recordar(titol));

// Totes dues imprimeixen:
// Iván ha de fer: Redissenyar la sala polivalent
// Iván ha de fer: Pressupost de la fusteria

Una tercera opció vàlida, específica de forEach, és aprofitar el seu segon paràmetre: pendents.forEach(agenda.recordar, agenda);.

Exercici 3

const tauler = {
  nom: 'Taller Nómada',
  avui: AVUI,
  tasques: [ /* les sis tasques del backlog */ ],

  obertes() {
    const resultat = [];
    for (const tasca of this.tasques) {
      if (tasca.estat !== 'feta') resultat.push(tasca);
    }
    return resultat;
  },

  horesDe(persona) {
    let total = 0;
    for (const tasca of this.obertes()) {       // reaprofita el mètode anterior
      if (tasca.responsable === persona) total += tasca.horesEstimades;
    }
    return total;
  },

  informePerPersona() {
    const informe = {};
    for (const tasca of this.obertes()) {
      const clau = tasca.responsable;
      informe[clau] = (informe[clau] ?? 0) + tasca.horesEstimades;
    }
    return informe;
  }
};

console.log(tauler.horesDe('Iván'));       // 25
console.log(tauler.horesDe('Marta'));      // 6
console.log(tauler.horesDe('Lucía'));      // 14
console.log(tauler.informePerPersona());   // { Iván: 25, Marta: 6, Lucía: 14 }

Comprovació: 25 + 6 + 14 = 45 h obertes, exactament les del backlog canònic (les 3 h d'«Inventari de tintes» no compten perquè està feta). Dos detalls del codi: informe[clau] fa servir claudàtors perquè la clau és dins d'una variable (04-01), i (informe[clau] ?? 0) resol la primera vegada, quan la clau encara no existeix i retornaria undefined. A 04-05 faràs exactament aquest mateix agrupament amb reduce en quatre línies.

Conclusió

Un mètode no és més que una funció desada en una propietat, i s'escriu amb la sintaxi abreujada metode() {}. El que el fa especial és this, i ara tens l'única regla que necessites: this depèn de com es crida la funció, no d'on es va escriure. Amb les quatre formes d'invocació al cap —crida simple (undefined en mode estricte), com a mètode (el receptor), amb new (l'objecte nou, que desenvoluparàs al Mòdul 5) i amb call/apply/bind (el que tu diguis)— qualsevol this misteriós deixa de ser-ho: n'hi ha prou de mirar la crida.

Has construït l'objecte tauler de Taller Nómada, amb cercarPerId, afegir, canviarEstat, resum i linia, comprovant que els mètodes es criden entre si a través de this, que retornar this permet encadenar operacions i que els errors es llancen amb el throw new Error de 02-05. Has diagnosticat el problema clàssic —perdre this en passar un mètode com a callback— i tens les tres solucions amb els seus avantatges i inconvenients. I has tancat el deute de 03-02: la funció fletxa no té this propi, l'hereta de l'àmbit on es va escriure, cosa que la fa inútil com a mètode d'un objecte literal i perfecta com a callback dins d'un mètode.

Fixa't ara en què ha estat el més incòmode d'aquesta lliçó. No ha estat this: han estat els bucles. cercarPerId recorre a mà fins que troba; resum acumula quatre variables en un for; horesDe filtra amb un if dins d'un altre bucle. L'objecte ja està ben modelat, però la llista de tasques encara es maneja amb les eines del Mòdul 2. Això canvia a partir de la lliçó següent, Arrays: Conceptes Bàsics i Mètodes, on estudiaràs l'array a fons: com es crea, com es mesura, i sobretot la distinció que més disgustos evita en JavaScript —mètodes que muten l'array davant de mètodes que en retornen un de nou—, amb les etiquetes d'una tasca com a banc de proves.

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