Kodokon kodokon.com

this, prototypes et classes

Comprenez la résolution dynamique de this, la chaîne de prototypes et ce que les classes ajoutent réellement au modèle objet.

10 min · 3 questions

Ouvrir cette leçon dans Kodokon

La valeur de this se décide au site d'appel, pas à la déclaration. Quatre règles, par priorité décroissante : appel avec new, liaison explicite (call, apply, bind), appel comme méthode (obj.fn()), et appel libre (fn()), qui donne undefined en mode strict. Le bug le plus fréquent du métier en découle : extraire une méthode de son objet casse la liaison implicite.

JAVASCRIPT
const user = {
  name: "Ada",
  greet() {
    return "Bonjour, " + this.name;
  },
};
console.log(user.greet()); // "Bonjour, Ada"
const detached = user.greet;
// detached(); // TypeError : this vaut undefined
const bound = user.greet.bind(user);
console.log(bound()); // "Bonjour, Ada"
La liaison implicite disparaît dès que la méthode est extraite.

Les fonctions fléchées ne possèdent pas de this : elles capturent lexicalement celui de la portée englobante, comme une closure. C'est idéal pour les callbacks, mais contre-productif pour les méthodes d'objet littéral, où this pointera vers la portée extérieure. Sous le capot, tout objet délègue via sa chaîne de prototypes : une propriété absente est cherchée de maillon en maillon jusqu'à null.

JAVASCRIPT
function Animal(name) {
  this.name = name;
}
Animal.prototype.describe = function () {
  return this.name + " est un animal";
};
const dog = new Animal("Rex");
console.log(dog.describe()); // "Rex est un animal"
console.log(Object.getPrototypeOf(dog) ===
  Animal.prototype); // true
console.log(dog.hasOwnProperty("describe")); // false
describe vit sur le prototype, partagé par toutes les instances.

La syntaxe class ne change pas ce modèle : elle le rend lisible. Les méthodes déclarées dans le corps de la classe atterrissent sur Constructor.prototype et sont donc partagées. Les champs d'instance (dont les fléchées assignées comme champs) sont recréés par instance : liaison de this garantie, mais coût mémoire multiplié. Les champs #privés offrent enfin une confidentialité vérifiée par le moteur, contrairement à la convention _underscore.

JAVASCRIPT
class BankAccount {
  #balance = 0;
  deposit(amount) {
    if (amount <= 0) throw new Error("Montant invalide");
    this.#balance += amount;
    return this;
  }
  get balance() {
    return this.#balance;
  }
}
const account = new BankAccount();
account.deposit(50).deposit(25);
console.log(account.balance); // 75
Champ privé vérifié par le moteur et API chaînable.

Quiz de validation

Vérifiez que vous avez bien retenu les points clés de cette leçon.

  1. En mode strict, que vaut this lors d'un appel libre fn() sans objet ni liaison explicite ?
    • globalThis
    • undefined
    • L'objet dans lequel fn a été déclarée
    • null
  2. Où sont stockées les méthodes déclarées dans le corps d'une classe (hors champs) ?
    • Sur chaque instance, recopiées à la construction
    • Sur Constructor.prototype, partagées par toutes les instances
    • Dans une portée interne inaccessible
  3. Quelle est la particularité d'une fonction fléchée vis-à-vis de this ?
    • Elle lie this à l'objet qui l'appelle, comme une méthode
    • Elle n'a pas de this propre et capture celui de la portée englobante
    • Elle lie toujours this à globalThis
    • Elle interdit tout accès à this