Dans la plupart des langages de programmation, le mot-clé this est utilisé dans le code non-statique d'une classe pour se référer à l'objet courant.
Par exemple:
Dans cet exemple, pendant l’exécution du constructeur de la classe Car, la variable this a comme valeur l'objet qui est en train d'être construit.
Dans ce genre de contexte, il est très clair à quel objet si réfère la variable this dans le code des constructeurs et méthodes d'une classe. Mais dans la vraie vie, vous allez rencontrer des références à this dans d'autres contextes où son usage sera moins évident, et là où vous risquerez d'introduire des bugs en modifiant du code.
Dans cet article, nous verrons d'autres contextes où ce mot clé pourra être utilisé et sa signification.
Avant de commencer...
Il faut se rappeler que le Javascript n'est pas un langage orienté objet classique et que la plupart du temps c'est ce qui rend la compréhension du mot clé this difficile. Pour commencer, lorsque l'on lit du code Javascript il faut se rappeler qu'il n'y a que du code et des objets, tout les autres concepts ne sont que du sucre syntaxique!
Par exemple, on pourrait réécrire le code précédent comme:
Ce code fait la même chose que le code précédent. Là on voit que la classe Car n'est qu'un ensemble de fonctions qui manipule un objet mystérieux dans une variable this. Un appel à fonction sur un objet construit à partir d'une classe n'est qu'un appel à la méthode call de la fonction (qui à l’exécution est un objet aussi). Le premier paramètre passé à la fonction call n'est que la valeur assumé par la variable this pendant l’exécution de la méthode. Le mot clé new ne fait qu’appeler la fonction constructeur sur un objet vide.
Le bon réflexe a avoir : dans quel contexte le code courant est appelé?
Quand on essaie de comprendre du code qui utilise le mot clé this, le bon réflexe est donc de regarder le contexte où le code qui utilise this a été appelé.
Dans un appel .call/apply
Comme on a montré dans l'exemple précédent, une fonction est un objet. On utilisera les fonctions call et apply pour définir directement la valeur de this à l’exécution.
Dans l'exemple suivant on affichera l'objet passé en paramètre dans la console.
Dans du code qui n'est pas dans une fonction
Il y a deux cas à considérer:
si on est en strict mode, this vaut undefined;
si on en'est pas en strict mode, this est l'objet global en NodeJS ou l'objet window dans un navigateur.
Dans l'exemple suivant, la valeur affichée dans le console dépendra du mode dans lequel s’exécute le code.
Attention, cette règle est valable aussi pour une fonction définie à l'intérieur d'une autre fonction !
Dans l'exemple suivant, this n'est pas l'objet hello world, mais global, window ou undefined selon le mode d’exécution de ce code!
Dans un appel à new où à la notation `.` pour accéder à un getter/setter ou à une méthode
Dans ce cas, Javascript se comporte comme prévu, et this a la valeur de l'objet crée (pour un appel new) ou l'objet avant le `.` (pour les autres cas). Dans l'exemple suivant, on affichera un objet Car dans la console.
Dans une fonction fléchée
Dans ce cas, la valeur de this est figée à la valeur de this au moment de la création de la fonction.
Dans l'exemple suivant, lors du premier appel, on affichera helloWorld deux fois; lors du deuxième appel, on affichera l'objet global (car exécuté en NodeJS) deux fois; lors du premier appel isolé, on affichera l'objet helloWorld, lord du deuxième, on affichera l'objet global.
Comparons cet exemple avec l'exemple suivant, où on remplacera p par une fonction non fléchée.
Dans ce cas, la variable this dans p vaudra toujours global, tandis que celle dans f aura une valeur différente dans chaque appel. Dans le premier appel, elle vaudra helloWorld, dans les autres, global.
Après un appel bind()
La méthode bind() d'une fonction sert à fixer la valeur de this pour tous les appels à cette fonction, indépendamment du contexte.
Dans le code suivant, on crée deux fonctions b et c, c est bound à l'objet someObject tandis que b ne l'est pas.
On exécute les deux fonctions dans deux contextes: avec apply et avec la notation `.` pour appeler une méthode d'un objet.
La sortie après l'exécution de ce code est la suivante.
On voit que pour c, this vaut toujours someObject, peu importe le contexte d'appel. Pour b, la valeur de dépends du contexte dans lequel la fonction est appelé.
Pour aller plus loin...
Cet article est encore trop court pour parler de tous les détails liés à l'utilisation du mot clé this, pour aller plus loin, je vous propose de vous référer à la documentation mozilla de ce mot clé pour avoir plus de détails et plus d'exemples.
Pour les adeptes de ES6, la documentation mozilla des fonctions fléchées peut aussi aider à comprendre les choix d'implémentation derrière le fonctionnement du mot clé this dans ces fonctions.
Je vous laisse trois articles intéressants sur le sujet:
Gentle explanation of 'this' keyword in JavaScript, https://dmitripavlutin.com/gentle-explanation-of-this-in-javascript/
Understand JavaScript’s “this” With Clarity, and Master It, http://javascriptissexy.com/understand-javascripts-this-with-clarity-and-master-it/
JavaScript’s Apply, Call, and Bind Methods are Essential for JavaScript Professionals, http://javascriptissexy.com/javascript-apply-call-and-bind-methods-are-essential-for-javascript-professionals/
Et pour finir, un livre partiellement dédié au sujet:
You Don't Know JS: this & Object Prototypes, https://github.com/getify/You-Dont-Know-JS/tree/master/this%20%26%20object%20prototypes