this dépend de QUI appelle
En JavaScript, this n'est pas figé : sa valeur dépend de comment la fonction est appelée, pas d'où elle est écrite. Dans une méthode appelée normalement (objet.methode()), this est l'objet. Mais si tu détaches la méthode (la passes en callback), this se perd.
class Compteur {
valeur = 0;
incr() { this.valeur++; console.log(this.valeur); }
}
const c = new Compteur();
c.incr(); // 1 → this = c, OK
const f = c.incr; // on DÉTACHE la méthode
// f(); // ❌ this est undefined → erreur
setTimeout(c.incr, 100); // ❌ même problème : appelé "tout seul"
C'est LE piège que tout débutant rencontre, surtout avec les addEventListener et les setTimeout.
La solution : les arrow functions capturent this
Une arrow function (=>) ne crée pas son propre this : elle garde celui de l'endroit où elle est écrite (this « lexical »). D'où le réflexe : entoure l'appel d'une arrow.
setTimeout(() => c.incr(), 100); // ✅ l'arrow garde le contexte, c.incr() est bien appelé sur c
// Dans une classe, définir une méthode-champ en arrow fige aussi this :
class Bouton {
clics = 0;
onClick = () => { this.clics++; }; // this sera TOUJOURS le bouton
}
Les anciennes solutions .bind(c), .call(c), .apply(c) existent encore (elles forcent this), mais l'arrow function est aujourd'hui le réflexe le plus simple.
Vois le piège (et le fix)
Sous le capot : les prototypes
Avant les classes (2015), JavaScript faisait déjà de la POO… avec les prototypes. Chaque objet a un objet « parent » (son prototype) où JS va chercher une propriété ou une méthode s'il ne la trouve pas sur lui-même. C'est la chaîne de prototypes.
La vérité qui surprend : les classes JS ne sont que du « sucre syntaxique » par-dessus les prototypes. class Compte { deposer() {} } met en réalité deposer sur Compte.prototype, partagé par toutes les instances. Tu n'as pas besoin de manipuler les prototypes à la main (la syntaxe class est plus claire), mais savoir qu'ils sont là explique pourquoi l'héritage marche et pourquoi une méthode n'est pas dupliquée dans chaque objet.
À retenir : class = présentation moderne ; prototype = mécanisme réel en dessous. Comprendre ça, c'est ne plus jamais être surpris par le comportement des objets JS.
__proto__ jusqu'à la trouver, ou jusqu'à null.Tes classes sont propres. Reste à découper ton code en fichiers réutilisables, au lieu d'un seul gros script : les ES Modules.
Leçon 3 : les ES Modules →this depends on WHO calls
In JavaScript, this isn't fixed: its value depends on how the function is called, not where it's written. In a method called normally (object.method()), this is the object. But if you detach the method (pass it as a callback), this gets lost.
class Compteur {
valeur = 0;
incr() { this.valeur++; console.log(this.valeur); }
}
const c = new Compteur();
c.incr(); // 1 → this = c, OK
const f = c.incr; // we DETACH the method
// f(); // ❌ this is undefined → error
setTimeout(c.incr, 100); // ❌ same problem: called "on its own"
It's THE trap every beginner hits, especially with addEventListener and setTimeout.
The fix: arrow functions capture this
An arrow function (=>) doesn't create its own this: it keeps the one from where it's written ("lexical" this). Hence the reflex: wrap the call in an arrow.
setTimeout(() => c.incr(), 100); // ✅ the arrow keeps the context, c.incr() runs on c
// In a class, defining a field-method as an arrow also pins this:
class Bouton {
clics = 0;
onClick = () => { this.clics++; }; // this will ALWAYS be the button
}
The old solutions .bind(c), .call(c), .apply(c) still exist (they force this), but the arrow function is now the simplest reflex.
See the trap (and the fix)
Under the hood: prototypes
Before classes (2015), JavaScript already did OOP… with prototypes. Each object has a "parent" object (its prototype) where JS looks for a property or method if it can't find it on the object itself. That's the prototype chain.
The surprising truth: JS classes are just "syntactic sugar" over prototypes. class Compte { deposer() {} } actually puts deposer on Compte.prototype, shared by all instances. You don't need to handle prototypes by hand (the class syntax is clearer), but knowing they're there explains why inheritance works and why a method isn't duplicated in every object.
Takeaway: class = modern presentation; prototype = the real mechanism underneath. Understand that, and you'll never be surprised by JS object behavior again.
__proto__ until it finds it, or hits null.Your classes are clean. Now split your code into reusable files instead of one big script: ES Modules.
Lesson 3: ES Modules →Sans remonter dans la leçon : de quoi dépend la valeur de this, pourquoi const f = c.incr; f() casse, et comment une arrow function répare le problème ?
this dépend de comment la fonction est appelée, pas d'où elle est écrite. c.incr() : this = c. Mais const f = c.incr; f() détache la méthode : elle est appelée "toute seule", donc this vaut undefined (mode strict des classes) et this.valeur lève une erreur. L'arrow () => c.incr() ne crée pas son propre this : à l'intérieur on rappelle explicitement c.incr(), donc this redevient c.L'IA te propose ce composant : un compteur de clics qui branche sa méthode incr directement comme écouteur. Ton rôle de relecteur : accepter tel quel, ou rejeter, et dire pourquoi.
class Compteur {
valeur = 0;
incr() { this.valeur++; }
}
const c = new Compteur();
bouton.addEventListener("click", c.incr);
c.incr passé seul est détaché de c. Au clic, addEventListener appelle la fonction avec this = l'élément DOM (le bouton), pas l'instance ; this.valeur++ écrit alors valeur sur le bouton et le vrai compteur ne bouge jamais. Le fix : envelopper dans une arrow, addEventListener("click", () => c.incr()), ou définir incr comme champ-arrow dans la classe pour figer this.