To be or not to be ? This is the question…
Si dans la majorité des langages orientés objet le mot clé this fait référence à l’instance courante d’une classe, il en va un peu différemment en JavaScript. En effet, contrairement à PHP, C++ ou Java, la valeur de this au moment de l’exécution d’une fonction dépend de son contexte et de la manière dont celle-ci est appelée. Ce comportement particulier vaut à this d’être parfois mal perçu en JS par les personnes venues de l’orienté objet pur.
Dans cet article, nous nous limiterons au comportement de this dans les fonctions conventionnelles, mettant en jeu le mot clé function ou la syntaxe concise au sein d’un objet. En effet, le comportement de this au sein des fonctions fléchées est un peu différent.
This en JS : show me your context !
Premièrement, il convient de rappeler que this est un opérateur et donc que celui-ci retourne une valeur. En JS, la valeur de this est intimement liée à son contexte d’exécution. En dehors de toute fonction, this pointe sur un objet qui dépend de l’environnement d’exécution. Au sein d’un navigateur par exemple, le this référence l’objet window. Dans un runtime comme Node.js, this peut faire référence à global ou à exports (si l’on se trouve dans le contexte d’un module). Ceci dit, quel que soit le mode d’exécution de JS, this se comporte toujours de cette manière hors d’une fonction.
This : une histoire de mode…
Pour parler de this en JavaScript il faut rappeler ce que sont les modes strict et par extension le mode non-strict. Introduit par le standard ES5, le mode strict propose une variante restrictive de JavaScript. Ainsi, avec ce mode, certains comportements natifs du langage deviennent impossibles ou davantage verbeux. Si l’implémentation du mode strict par défaut n’est pas la norme des navigateurs, c’est celle des transpilers comme Babel par exemple. Sans préciser au script que l’on cherche à exécuter du JavaScript en mode strict, on l’exécute en mode non-strict. Ceci dit, comme nous l’avons vu, le mode n’altère pas le comportement de this dans le contexte global, ce qui est différent de son comportement au sein d’une fonction.
This dans les fonctions standard
Au sein d’une fonction, selon le mode utilisé, this ne contient pas la même référence. Ainsi, dans le mode strict, il est évalué à undefined, quand il continue à référencer l’objet global en mode laxiste (ou non-strict). Ce comportement vise à empêcher toute altération de l’objet global par modification du this au sein d’une fonction.
Toujours à l’intérieur d’une fonction, la valeur de this dépend de la manière dont on appelle la fonction. Quand une fonction est invoquée, un environnement local d’exécution est créé par le moteur JS. Cet environnement contient de multiples définitions, comme par exemple les arguments, mais aussi le this local. Cet environnement local prend le pas sur le contexte global.
Ainsi, si on appelle une fonction en faisant référence à un objet via un accesseur (comme le . ou les [ ]) et que celle-ci est directement invoquée, alors this contient une référence à l’objet situé à gauche de l’accesseur. Dans tous les autres cas, on “brise” le lien entre this et l’objet : this fait référence à undefined (si on est en mode non-strict) ou lève une TypeError, en mode strict.
Ce comportement est parfois déroutant, notamment lors du passage de fonctions contenant une implémentation de this en callback d’autres fonctions. En effet, dans cette configuration, nous nous retrouvons bien dans le second cas de figure décrit dans le paragraphe précédent. Heureusement, plusieurs méthodes permettent de sauvegarder le “comportement attendu” de this. S’il existe plusieurs méthodes pour ce faire, nous aurons toutefois l’occasion de les aborder lors d’un prochain article.
0 commentaires