JavaScript est un langage multi-paradigme qui prend en charge la programmation orientée objet et la liaison de méthode dynamique - un concept puissant qui permet à la structure du code JavaScript de changer pendant l'exécution du programme. Cela donne aux développeurs de sérieuses opportunités, cela rend le langage flexible, mais vous devez payer pour tout. Dans ce cas, vous devez payer avec l'intelligibilité du code. Une contribution significative à ce prix est apportée par le
this
, autour du comportement duquel beaucoup de choses ont été collectées qui peuvent dérouter le programmeur.

Liaison de méthode dynamique
La liaison dynamique vous permet de spécifier, lors de l'exécution du programme, et non lors de la compilation, la méthode qui doit être appelée lors de l'exécution d'une certaine commande. En JavaScript, ce mécanisme est implémenté à l'aide du
this
et de la chaîne de prototypes. En particulier, la valeur spécifique de
this
à l'intérieur de la méthode est déterminée lors de l'exécution et les règles de détermination de cette valeur varient en fonction de la façon dont la méthode a été déclarée.
Jouons un jeu. Je l'appelle "Qu'est-ce qui est écrit ici?". Voici sa première option - le code du module ES6:
const a = { a: 'a' }; const obj = { getThis: () => this, getThis2 () { return this; } }; obj.getThis3 = obj.getThis.bind(obj); obj.getThis4 = obj.getThis2.bind(obj); const answers = [ obj.getThis(), obj.getThis.call(a), obj.getThis2(), obj.getThis2.call(a), obj.getThis3(), obj.getThis3.call(a), obj.getThis4(), obj.getThis4.call(a) ];
Avant de continuer à lire, réfléchissez à ce qui se trouvera dans le tableau des réponses et notez les réponses. Après cela, testez-vous en
answers
tableau de
answers
aide de
console.log()
. Avez-vous réussi à «décrypter» correctement la valeur de
this
dans chacun des cas?
Nous analyserons ce problème, en commençant par le premier exemple. La construction
obj.getThis()
renvoie
undefined
. Pourquoi? Cette fonction de flèche ne peut pas être liée. Ces fonctions utilisent
this
partir de leur portée lexicale environnante. La méthode est appelée dans le module ES6, dans sa portée lexicale
this
ne sera pas
undefined
. Pour la même raison,
undefined
renverra
undefined
un appel à
obj.getThis.call(a)
. La valeur de
this
lorsque vous travaillez avec des fonctions fléchées ne peut pas être réaffectée même avec
.call()
ou
.bind()
. Cette valeur correspondra toujours à
this
partir de la portée lexicale, dans laquelle ces fonctions sont situées.
La commande
obj.getThis2()
montre comment travailler avec
this
lors de l'utilisation de méthodes d'objet normales. Si
this
pas lié à une méthode similaire, et à condition que cette méthode ne soit pas une fonction de flèche, c'est-à-dire qu'elle prend en charge
this
liaison, le mot clé
this
est lié à l'objet pour lequel la méthode est appelée en utilisant la syntaxe d'accès aux propriétés de l'objet via point ou en utilisant des crochets.
La construction
obj.getThis2.call(a)
est déjà un peu plus délicate à comprendre. La méthode
call()
vous permet d'appeler une fonction avec une valeur donnée de
this
, qui est indiquée comme argument optionnel. En d'autres termes, dans ce cas,
this
est extrait du paramètre
.call()
, par conséquent, l'appel à
obj.getThis2.call(a)
renvoie l'objet
a
.
Utilisation de la commande
obj.getThis3 = obj.getThis.bind(obj);
nous essayons de nous lier à
this
méthode, qui est une fonction de flèche. Comme nous l'avons déjà découvert, cela ne peut pas être fait. Par conséquent, les appels à
obj.getThis3()
et
obj.getThis3.call(a)
renvoient
undefined
.
Des méthodes qui sont des fonctions ordinaires peuvent être attachées à
this
, donc
obj.getThis4()
, comme prévu, renvoie
obj
. Un appel à
obj.getThis4.call(a)
renvoie
obj
et non, comme vous pouvez vous y attendre,
a
. Le fait est qu'avant d'
obj.getThis4 = obj.getThis2.bind(obj);
cette commande, nous l'avons déjà lié avec la commande
obj.getThis4 = obj.getThis2.bind(obj);
. Par conséquent, lors de l'exécution de
obj.getThis4.call(a)
, l'état de la méthode dans laquelle il se trouvait après la prise en compte de la première liaison est pris en compte.
Utiliser cela en classe
Voici la deuxième version de notre jeu - la même tâche, mais maintenant basée sur les classes. Ici, nous utilisons la syntaxe pour déclarer les champs de classe publique (pour le moment, la
proposition de cette syntaxe est au troisième stade d'approbation, elle est disponible par défaut dans Chrome, vous pouvez l'utiliser avec
@babel/plugin-proposal-class-properties
).
class Obj { getThis = () => this getThis2 () { return this; } } const obj2 = new Obj(); obj2.getThis3 = obj2.getThis.bind(obj2); obj2.getThis4 = obj2.getThis2.bind(obj2); const answers2 = [ obj2.getThis(), obj2.getThis.call(a), obj2.getThis2(), obj2.getThis2.call(a), obj2.getThis3(), obj2.getThis3.call(a), obj2.getThis4(), obj2.getThis4.call(a) ];
Avant de continuer à lire, pensez au code et notez votre vision de ce qui va tomber dans le tableau de
answers2
.
Vous avez terminé?
Ici, tous les appels de méthode, à l'exception de
obj2.getThis2.call(a)
,
obj2.getThis2.call(a)
une référence à l'instance de l'objet. Le même appel renverra l'objet
a
. Les fonctions fléchées tirent toujours
this
de la portée lexicale. La différence entre cet exemple et le précédent est la différence dans la portée d'où
this
est tiré.
À savoir, nous travaillons ici avec les propriétés de classe, qui déterminent le comportement de ce code.
Le fait est que lors de la préparation du code pour l'exécution, les valeurs sont écrites dans les propriétés des classes comme ceci:
class Obj { constructor() { this.getThis = () => this; } ...
En d'autres termes, il s'avère que la fonction flèche est déclarée dans le contexte de la fonction constructeur. Puisque nous travaillons avec une classe, la seule façon de l'instancier est d'utiliser le
new
mot-clé (si vous oubliez ce mot-clé, un message d'erreur sera affiché).
Les tâches les plus importantes résolues par le
new
mot clé sont de créer une nouvelle instance de l'objet et de la lier au constructeur. Cette fonctionnalité, compte tenu de ce dont nous avons déjà parlé dans la section précédente, devrait vous aider à comprendre ce qui se passe.
Résumé
Avez-vous terminé les tâches décrites dans cet article? Une bonne compréhension du comportement de
this
mot clé en JavaScript vous fera gagner une tonne de temps lors du débogage, lors de la recherche de raisons non évidentes d'erreurs obscures. Si vous avez répondu incorrectement à certaines des questions, cela signifie qu'il vous sera utile de vous entraîner.
Testez l'exemple de code, puis réessayez, etc., jusqu'à ce que vous puissiez répondre correctement à toutes les questions. Après avoir compris vous-même, trouvez quelqu'un prêt à vous écouter et dites-lui pourquoi les méthodes des tâches renvoient exactement ce qu'elles renvoient.
Si tout cela vous semble plus compliqué que prévu, sachez que vous n'êtes pas seul dans ce domaine. J'ai testé pas mal de développeurs pour connaître les fonctionnalités de
this
, et je pense qu'un seul d'entre eux était absolument précis dans toutes leurs réponses.
Ce sous-système du langage, qui au tout début ressemblait à une recherche dynamique de méthodes pouvant être influencées à l'aide de
.call()
,
.bind()
ou
.apply()
, a commencé à paraître beaucoup plus compliqué après l'apparition des fonctions fléchées et des classes.
Apparemment, il sera utile de noter les principales caractéristiques des classes et des fonctions fléchées en termes d'utilisation. N'oubliez pas que les fonctions fléchées utilisent toujours
this
partir de leur portée lexicale, et le
this
dans les classes est en fait lié à la fonction constructeur de la classe. Et si jamais vous sentez que vous ne savez pas exactement à quoi
this
renvoie, utilisez le débogueur pour vérifier vos hypothèses à ce sujet.
N'oubliez pas que vous pouvez faire beaucoup de choses en JavaScript sans utiliser
this
dans votre code. L'expérience me dit que presque tout code JS peut être réécrit sous la forme de fonctions pures qui acceptent tous les arguments avec lesquels il travaille, sous la forme d'une liste de paramètres explicitement spécifiée (
this
peut être interprété comme un paramètre implicitement spécifié avec un état mutable). La logique contenue dans les fonctions pures est déterministe, ce qui améliore leur testabilité. De telles fonctions n'ont pas d'effets secondaires, ce qui signifie que lorsque vous travaillez avec elles, contrairement à la manipulation, il est peu probable que vous «cassiez» quoi que ce soit en dehors. Chaque fois que vous changez
this
, vous êtes confronté à un problème potentiel, à savoir que quelque chose qui en dépend peut cesser de fonctionner correctement.
Malgré ce qui précède, il convient de noter qu'il s'agit d'un concept utile. Par exemple, elle peut être appliquée afin d'organiser le partage d'une certaine méthode par une multitude d'objets. Même dans la programmation fonctionnelle,
this
peut être utile pour appeler d'autres méthodes d'un objet à partir d'une méthode, ce qui vous permet de créer quelque chose de nouveau basé sur des constructions existantes.

