Liaison de this en JavaScript : ce qui décide de sa valeur à l'appel

La valeur de this n'est pas fixée à l'écriture d'une fonction, mais à chaque appel. Quatre formes d'appel donnent quatre résultats différents.
4 min de lecture
Believemy logo

Une méthode fonctionne parfaitement, puis on la passe en argument et elle échoue. Le code n'a pas changé d'une ligne. Ce qui a changé, c'est la façon dont elle est appelée.

C'est la particularité de this en JavaScript : sa valeur n'est pas décidée là où la fonction est écrite, mais là où elle est appelée. On appelle cette résolution la liaison de this.


Définition

La liaison de this est la règle qui détermine, au moment de l'appel, quel objet la fonction désignera par this. Quatre formes d'appel existent, et une cinquième qui échappe entièrement à la règle.

Forme de l'appelCe que vaut this
new Compte()L'objet fraîchement créé
compte.presenter()L'objet écrit avant le point
presenter.call(compte)Le premier argument fourni
presenter()undefined en module, l'objet global sinon
() => ...Celui de l'endroit où la flèche a été écrite

Ce tableau à deux colonnes se lit de haut en bas : la première forme qui correspond à l'appel l'emporte.

Ce que vaut this selon la forme de l'appelTableau à deux colonnes. new Compte() donne l'objet fraîchement créé, compte.presenter() l'objet écrit avant le point, presenter.call(obj) le premier argument reçu, presenter() undefined en module, et une fonction fléchée reprend le this du code qui l'entoure. La ligne mise en avant est l'appel détaché, qui a perdu son objet.Forme de l'appelCe que vaut thisnew Compte()L'objet fraîchement créécompte.presenter()L'objet avant le pointpresenter.call(obj)Le premier argument reçupresenter()undefineden module(…) => …Celui du code qui l'entourepresenter() : la méthode a quitté son objetUn appel sans point n'a aucun objet à désigner


Le cas qui casse, et pourquoi

JAVASCRIPT
const compte = {
  nom: "Believemy",
  presenter() {
    return this;
  },
};

console.log(compte.presenter() === compte); // true

const detache = compte.presenter;
console.log(detache() === compte);          // false

const relie = compte.presenter.bind(compte);
console.log(relie() === compte);            // true

La méthode n'appartient pas à l'objet, elle y est simplement rangée. Sortie de son emplacement, elle devient une fonction ordinaire appelée sans point, donc sans objet à désigner. Dans un module, this y vaut undefined et toute lecture de propriété lève une TypeError.


Les trois façons de refixer la liaison

  • bind() renvoie une nouvelle fonction dont le this est figé. C'est la solution quand la fonction part ailleurs.
  • call() et apply() appellent immédiatement en imposant le this. Les deux ne diffèrent que par la façon de passer les arguments.
  • La Fonction fléchée n'a pas de this propre : elle reprend celui de son environnement d'écriture, ce qui règle le problème sans y penser.
JAVASCRIPT
const minuteur = {
  nom: "chrono",
  demarrer() {
    setTimeout(() => {
      console.log("fini : " + this.nom);
    }, 10);
  },
};

minuteur.demarrer(); // fini : chrono
Bon à savoir

Avec une fonction classique à la place de la flèche, this.nom ne désignerait plus le minuteur : la fonction de rappel est appelée par le moteur, sans objet devant.


Questions fréquentes

Question

Pourquoi ma méthode de classe perd-elle son this en argument ?

Parce que passer objet.methode en argument transmet la fonction seule, détachée de l'objet. La correction consiste à passer objet.methode.bind(objet), ou à envelopper l'appel dans une flèche. Dans une class, déclarer la méthode comme un champ fléché fige la liaison une fois pour toutes.


Question

Quelle différence entre call() et apply() ?

Aucune sur le résultat. call() reçoit les arguments un par un, apply() les reçoit dans un tableau. Depuis l'arrivée du Spread (...), apply() a perdu presque tout intérêt, puisque fonction.call(cible, ...liste) fait la même chose de façon plus lisible.


Question

Peut-on rattacher une fonction fléchée à un autre objet ?

Non, et c'est voulu. Une flèche ne possède pas de liaison propre, donc bind(), call() et apply() n'ont aucun effet sur son this. C'est exactement pour cela qu'elle est fiable comme fonction de rappel, et inadaptée comme méthode d'objet ou comme constructeur.

Termes connexes

Découvrez notre glossaire JavaScript

Tous les mots de JavaScript expliqués simplement : mots-clés, objets natifs, méthodes, erreurs et concepts. Définitions claires et exemples qui tournent, pour apprendre et pour se dépanner.

Partager cet article

Tu veux nous aider ? Fais un lien vers cet article sur tes réseaux ou encore mieux : sur ton site, dans un article ou dans ta newsletter.