close

JavaScript : Qu'est ce que this ? Que vaut this ?

#1 Qu'est-ce que this ? open

this est un opérateur et comme tout opérateur, il retourne une valeur.

  1. D'où vient cette valeur ? Cette valeur provient d'un contexte d'exécution. Il faut savoir qu'au lancement du script, et ensuite à chaque appel d'une fonction, un contexte d'exécution est placé en pile d'exécution.
  2. Qu'y a-t-il dans un contexte d'exécution ? Il y a la valeur de this ça je viens de le dire et il y a aussi des informations qui vont permettre à la fonction de s'exécuter, par exemple les arguments qui lui sont passés. Je ne détaille pas plus. Mais vous pouvez déjà comprendre qu'à chaque appel d'une fonction, étant donné que l'on change les arguments, eh bien, on va créer un nouveau contexte. Ce qu'il faut retenir ici, c'est l'idée, car en fait, il y a beaucoup plus d'informations que ça dans un contexte d'exécution.
  3. Qui gère cette valeur de this ? Qui l'affecte ? Eh bien, c'est le moteur JavaScript qui le fait et qui le fait pour nous.
  4. Alors c'est gentil, mais à quoi ça va me servir ? Par exemple quand vous instanciez une classe pour créer un nouvel objet et bien dans la fonction constructeur this va désigner ce nouvel objet. Autre exemple : quand vous passez un callback à un gestionnaire d'événement et bien dans ce callback this va désigner l'élément du document sur lequel est posé ce gestionnaire.
  5. Et si la valeur de this ne vous convient pas ? il faut que vous sachiez que vous pouvez la changer en utilisant les méthodes call, apply ou bind du constructeur Function. On voit ça dans un autre tuto.
  6. Que vaut this ? Pour pouvoir utiliser la valeur de this, vous devez être capable de prévoir ce que va faire le moteur JavaScript et pour cela, on va étudier dans ce tuto les situations les plus courantes dans lesquelles des fonctions vont être invoquées. Il faut aussi savoir que la valeur de this peut dépendre :
    • dans un très petit nombre de cas, de l'utilisation ou pas, du mode strict.
    • de l'environnement d'exécution de JavaScript, à savoir le navigateur ou un serveur.

Une précision au niveau du vocabulaire que j'utilise dans ce tuto : un objet étant l'instance d'une classe, j'utilise indifféremment les mots objet ou instance.

#2 This avec une fonction classique invoquée dans la portée globale open

On va commencer par un cas simple, celui d'une fonction déclarée et invoquée dans la portée globale. On va demander à cette fonction de nous retourner sa valeur de this.

Au préalable, une petite précision : Peu importe la manière dont la fonction est déclarée. Elle peut être déclarée comme une fonction classique ou comme une expression ou être une fonction auto invoquée. Cela ne change rien à la valeur de this.

Faisons un test avec une fonction qui nous retourne la valeur de this.

this dans la portée globale
Tester le code

On constate que le console.log affiche la valeur de l'objet global window. Il se trouve que window appartient à l'environnement "navigateur" du moteur JavaScript. Dans ces conditions, il est logique de se poser une question : Que donnera ce code si je l'exécute sous node.js, puisque sous node.js, nous avons un environnement "serveur" et que window n'existe pas ?

On fait un test et là, on constate qu'on obtient aussi une valeur globale, mais qui cette fois-ci vaut Object [global]. Voir ci-dessous le résultat d'une exécution sous Node.js depuis VS Code.

Exemple de valeur de this du côté de node

Maintenant, on continue nos tests en exécutant les mêmes codes, mais cette fois-ci en mode strict. Et dans ce cas, des deux côtés, this prend la valeur undefined.

this en mode strict
Tester le code

Au-dessus, on vient de voir les cas où la valeur de this dépend soit de l'environnement, soit de l'utilisation ou pas du mode strict. Maintenant, on va passer à des cas qui sont indépendants de ces deux situations.

#3 This dans le callback d'un gestionnaire d'événement open

Dans un gestionnaire d'événement, quand un callback passé en argument est invoqué, this pointe sur l'élément sur lequel le gestionnaire est posé.

Dans l'exemple ci-dessous, je place un élément HTML button pour créer un bouton. Et ensuite, je clique sur ce bouton.

Une petite remarque sur ce que l'on voit pour ne pas tout mélanger. Le console.log(this) vous affiche le code HTML du bouton. Mais si on veut être précis, this ici est une référence puisque le typeof this retourne object. Donc en réalité this pointe sur l'objet JavaScript qui correspond à cet élément HTML dans l'arbre DOM.

this pour un gestionnaire
Tester le code

#4 This sur un new open

On va regarder ce qui se passe sur un new. Je précise que c'est la même chose de faire un new sur une fonction constructeur ou sur une classe. Le this ici pointe sur un objet vide. Cet objet est une instance de la classe Obj. Alors, je ne le fais pas dans cet exemple, mais en situation courante, on se sert de cette valeur de this pour ajouter des propriétés à l'objet de manière à le construire.

Sur Chrome, je suis obligé de rafraîchir la page pour obtenir l'évaluation de this afin de voir apparaître sa valeur qui est ici égale à un objet vide.
this sur un new
Tester le code

#5 This avec une méthode d'un objet open

Dans l'exemple ci-dessous, je déclare une classe, je déclare sa fonction constructeur, je lui ajoute une propriété click qui est un booléen que j'initialise à la valeur false. Je crée la méthode set qui servira à placer la valeur de click à true. Ensuite, je crée un objet en instanciant la classe. Le but du truc, c'est de mémoriser le fait qu'il y a eu un click. Ensuite, j'appelle la méthode obj.set et je regarde la valeur de this. Dans ce cas, this vaut obj qui pointe sur l'instance qui vient d'être créée.

this pour la méthode d'un objet
Tester le code

Maintenant, je vais récupérer mon bouton avec son gestionnaire d'événement. Mon but, c'est toujours le même, à savoir, mémoriser le clic sur le bouton dans obj.

Pour ça, je vais mettre la méthode obj.set de l'objet comme callback du gestionnaire. Mais qu'est-ce qui va se passer, au moment de l'invocation du callback dans le gestionnaire ? La méthode set de obj trouve un this qui à la valeur but. C'est cette valeur qu'elle va utiliser, si bien que c'est avec but que va être exécuté le this.click=true et pas avec obj. En fait, on va faire en quelque sorte un but.click = true à la place d'un obj.click = true car dans ce cas et pour notre besoin la valeur de this n'est pas la bonne.

Tester le code
Une méthode dans un gestionnaire d'événement

Dans ces situations, le debugger peut nous aider, car il nous permet de voir ce que désigne this facilement. Il suffit de mettre un point d'arrêt dans la méthode set.

Pour cela, je vais dans Sources et je clique sur la ligne où je veux placer le point d'arrêt. Ici, je le place sur le this.click = true. Puis, je clique sur le bouton. Le debugger va s'arrêter sur le point d'arrêt sans exécuter l'instruction. Je peux voir dans la zone Scope que this désigne button. Je peux voir dans la console, que le console.log(this), affiche l'élément HTML button.

On peut voir this au debugger

Attention, cela ne veut pas dire que this est égal à button. Le debugger vous dit this deux points button et button, c'est une valeur qui appartient au HTML.

Je vais vous faire un schéma pour que vous compreniez bien les informations qui vous sont données. Nous avons this qui est égal à but. Donc but et this pointent tous les deux sur un même objet de l'arbre DOM. Un objet de constructeur HTMLButtonElement et qui correspond à l'élément HTML button.

Le debugger vous donne l'information utile. Le schéma vous détaille la chaîne.

Lecture des infos du debugger

Ce problème peut être facilement résolu, en appliquant la méthode bind au callback qui est passé au gestionnaire. Je détaille tout ça dans un autre tuto dans lequel je fais les méthodes call, apply, et bind du constructeur Function, dont le but est la maîtrise de la valeur de this.

Tester le code

#6 This avec une fonction fléchée open

Maintenant, dans la déclaration de notre classe, on modifie la méthode set et on remplace par une fonction fléchée.

Tester le code

On constate que le this reste pointé sur l'objet obj ce qui est logique, car une fonction fléchée hérite du this de la portée englobante à l'endroit de sa déclaration. Ici, dans l'objet, this pointe sur l'instance obj. La fonction fléchée est déclarée dans l'instance donc elle hérite de ce this et au moment de l'invocation, elle se le garde.

Vous pouvez constater ci-dessous, que la valeur a été mémorisée dans l'objet obj, bien que la méthode ait été invoquée dans le gestionnaire.

this avec des fonctions fléchées