* Très probablement, j'ai raté quelque chose, mais je suis sûr que les commentaires me le dirontJ'écris cet article pour mes besoins personnels. Il est prévu qu'il contienne les réponses à toutes les questions que les étudiants me posent à ce sujet. S'il est utile à quelqu'un d'autre, tant mieux.
Le contenu
- Présentation
- Idées fausses à ce sujet
- Comment déterminer la valeur de cette
Présentation
Le
this
-
this
est l'une des fonctionnalités les plus déroutantes du langage JavaScript. Venant de Java, il était destiné à aider à la mise en œuvre de la POO. J'ai écrit en Java pendant un certain temps, et je dois dire que pendant ce temps, j'ai peut-être une fois douté de ce à quoi
this
correspond à un endroit particulier du code. En JavaScript, de tels doutes peuvent surgir chaque jour - au moins jusqu'au moment où vous apprenez quelques règles simples mais non évidentes.
Idées fausses à this
sujet
Il existe plusieurs idées fausses courantes concernant ce mot clé. Je veux les dissiper rapidement avant d'en arriver au fait.
c'est un contexte lexical.Cette impression apparaît souvent chez les débutants. Il leur semble que c'est un objet dans lequel, comme les propriétés, toutes les variables de cette portée sont stockées. Cette idée fausse découle du fait que dans un cas particulier, grosso modo, il en est ainsi. Si nous sommes au plus haut niveau,
this
équivaut à
window
(dans le cas d'un script normal dans le navigateur). Et comme nous le savons, toutes les variables déclarées au niveau supérieur sont disponibles en tant que propriétés de
window
.
En général, ce n'est pas vrai. C'est facile à vérifier.
function test(){ const a = " , "; console.log(this.a); } test();
c'est l'objet auquel appartient la méthodeEncore une fois, cela est vrai dans de nombreux cas spécifiques, mais pas toujours. L'important est de savoir comment la fonction est appelée, et non s'il s'agit d'une propriété d'un objet. Cela est compréhensible même à partir d'une logique très simple: supposons que la même fonction soit une propriété de deux objets simultanément.
const f = function(){ console.log(this); } const object1 = { method: f }; const object2 = { method: f };
Alors, lequel de ces objets sera-ce elle?
Important! Même si un objet est créé à l'aide de classes ES6, cela ne garantit pas du tout que sa méthode l'aura toujours. Ne vous laissez pas berner par la ressemblance avec les classes des langues «normales».
c'est une technique Jedi qui, une fois apprise, doit être utilisée partoutIl est préférable d'éviter de l'utiliser si possible. Le seul cas où elle est pleinement justifiée est la POO. Ailleurs, l'utilisation de
this
n'est pas seulement un mal, mais généralement une exagération confondant le code. En substance,
this
s'agit d'un argument supplémentaire «moins le premier» de la fonction, qui y est transmis de manière compliquée et non évidente au débutant. Avec une probabilité élevée, il peut être remplacé par l'argument habituel, et il ne fera que s'améliorer.
Comment déterminer la valeur de cette
Ici, je vais essayer de donner un algorithme rigoureux et concis avec lequel même un codeur inexpérimenté pourra comprendre ce que
this
équivaut dans son cas particulier. Des explications plus verbeuses seront cachées sous les spoilers, afin de ne pas encombrer l'espace visuel.
- Sommes-nous à l'intérieur d'une fonction?
- Oui: voir l'article suivant.
- Non: c'est égal à un objet global .
CommentaireDans le code de niveau supérieur (pas à l'intérieur d'une fonction), this
fait toujours référence à un objet global. Dans le cas d'un script régulier dans le navigateur, il s'agit d'un objet window
. Mais en général, il existe différents cas.
- Sommes-nous à l'intérieur de la fonction flèche?
- Oui: la valeur de
this
est la même que dans la fonction un niveau plus haut (c'est-à-dire contenant celle-ci). Revenez à l'étape précédente et répétez l'algorithme pour cela. Si la fonction n'est contenue dans aucune autre, this
s'agit d'un objet global. - Non: voir le paragraphe suivant.
CommentaireL'une des principales caractéristiques des fonctions fléchées est ce que l'on appelle «lexical this
». Cela signifie que la valeur de this
dans la fonction flèche est déterminée uniquement par l'endroit (dans quel contexte lexical) il a été créé, et ne dépend pas de la façon dont il a ensuite été appelé. Parfois, ce n'est pas ce dont nous avons besoin, mais le plus souvent, cela rend les fonctions fléchées très pratiques et prévisibles.
- Cette fonction est-elle appelée en tant que constructeur (en utilisant le nouvel opérateur)?
- Oui:
this
fait référence à un nouvel objet qui est "en construction". - Non: voir le paragraphe suivant.
CommentairePeut-être vaut-il la peine de spécifier séparément le cas en ce qui concerne le constructeur de la classe ES6 héritée. Ensuite, avant d'appeler super()
, this
n'a pas de valeur (y accéder provoquera une erreur), et après avoir appelé super()
il est égal au nouvel objet de la classe parente.
- Cette fonction est-elle créée à l'aide de la liaison ?
- Oui: la valeur de
this
est égale à la valeur du premier argument que nous avons passé à la méthode bind
lors de la création de cette fonction. - Non: voir le paragraphe suivant.
CommentaireLa méthode bind
crée une copie de la fonction, corrigeant this
et, éventuellement, les premiers arguments pour elle. En fait, cela crée non seulement une copie de la fonction, mais, je cite, un «objet BoundFunction exotique». Son exotisme se manifeste, notamment, en ce que par un appel répété à bind
nous ne pouvons plus changer this
. Par conséquent, à proprement parler, la réponse dans ce paragraphe doit être formulée comme suit: si c'est le cas, alors this
est égal au premier argument du premier appel à bind
, qui a conduit à la création de cette fonction.
- Cette fonction est-elle passée quelque part en tant que rappel ou gestionnaire?
- Oui: le Seigneur seul sait ce que cela équivaudra une fois convoqué. Allez lire la documentation de la chose qui va la provoquer.
- Non: voir le paragraphe suivant.
CommentairePour une fonction non fléchée et liée, sa valeur dépend des circonstances dans lesquelles elle a été appelée. Si vous ne l'appelez pas personnellement, mais le transmettez quelque part,
this
valeur peut ou non être remplacée par une valeur inconnue pour vous.
Exemples:
`use strict` document.addEventListener('keydown', function(){ console.log(this); });
- Cette fonction est appelée à l'aide de l' application ou de l' appel ?
- Oui: dans ce cas,
this
équivaut au premier argument passé à la méthode correspondante. - Non: voir le paragraphe suivant.
CommentaireUne autre façon de définir explicitement this
. Plus précisément, deux. Cependant, en termes de this
pas de différence entre apply
et call
, la seule différence est la façon dont les autres arguments sont passés.
- Cette fonction est-elle obtenue en tant que valeur d'une propriété d'objet et immédiatement appelée?
- Oui:
this
équivaut à l'objet ci-dessus. - Non: voir le paragraphe suivant.
CommentaireEn fait, à partir de ce mécanisme (ainsi que de l'expérience de travail avec d'autres langues), les jambes croissent de la conviction que "c'est l'objet dont nous avons appelé la méthode". Je vais peut-être simplement écrire le code.
'use strict'; const object1 = { method: function(){ console.log(this); } } const object2 = { method: object1.method } object1.method();
- Le code s'exécute-t-il en mode strict? ('use strict', module ES6)
- Oui:
this
équivaut à undefined
. - Non: c'est égal à un objet global.
CommentaireSi nous arrivons à ce point,
this
défini par aucun des mécanismes qui permettent de le définir. Il existe diverses idées fausses sur la façon dont cela peut être adopté. Par exemple, lors des entretiens, ils me disent souvent une chose pareille:
const obj = { test: function(){ (function(){ console.log(this); })();
Ou, comme je l'ai dit dans la section «idées fausses», beaucoup de gens pensent que si une fonction est une méthode d'un objet créé à l'aide de classes ES6, alors ce sera toujours égal à cet objet qu'il contient. Ce n'est pas vrai non plus.
Donc, si nous arrivons à ce point, alors les autres circonstances d'appeler notre fonction n'ont pas d'importance. Et tout se résume à savoir si nous sommes en mode strict ou non.
Historiquement, par défaut, un objet global a été transmis à ces fonctions. Cette approche a ensuite été reconnue comme dangereuse. ES5 a introduit un mode strict qui résout de nombreux problèmes des versions antérieures d'ECMAScript. Il est inclus avec la directive «use strict» au début d'un fichier ou d'une fonction. Dans ce mode, la valeur "par défaut" de
this
n'est
undefined
.
Dans les modules ES6, le mode strict est activé par défaut.
Il existe également d'autres mécanismes pour inclure le mode strict, par exemple, dans NodeJS, le mode strict pour tous les fichiers peut être activé avec l'
--use-strict
.
C'est, en général, tout. La détermination de la valeur de
this
, bien sûr, est moins simple que nous le souhaiterions, mais ce n'est pas aussi difficile que cela puisse paraître. Apprenez cet algorithme en tant que table de multiplication - et vous n'aurez plus jamais de problèmes avec
this
. De telles choses.
L'utilisateur PS
Aingis a suggéré que lors de l'utilisation de la construction
with , l'objet qui lui est transmis en tant que contexte remplace l'objet global. Peut-être que je n'entrerai pas cela dans mon classificateur, car la chance de se rencontrer en 2019+ est plutôt petite. Mais en tout cas, c'est un point intéressant.
L'utilisateur PPS
rqrqrqrq a suggéré que
new
une priorité plus élevée que
bind
. La révision correspondante du classificateur a déjà été effectuée. Je vous remercie!