Ce mot-clé en JavaScript. Manuel complet *

* Très probablement, j'ai raté quelque chose, mais je suis sûr que les commentaires me le diront

J'é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.

image

Le contenu

  1. Présentation
  2. Idées fausses à ce sujet
  3. 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éthode

Encore 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 partout

Il 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.

  1. Sommes-nous à l'intérieur d'une fonction?

    • Oui: voir l'article suivant.
    • Non: c'est égal à un objet global .

    Commentaire
    Dans 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.
  2. 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.

    Commentaire
    L'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.
  3. 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.

    Commentaire
    Peut-ê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.
  4. 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.

    Commentaire
    La 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.
  5. 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.

    Commentaire
    Pour 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); }); //    this === document.    DOM- this  currentTarget [1, 2, 3].forEach(function(){ console.log(this); }); //         ,  undefined. ?     . 
  6. 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.

    Commentaire
    Une 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.
  7. 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.

    Commentaire
    En 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(); //    object1 -           object1['method'](); //  .        object2.method(); //    object2 -  " ",      ,         
  8. 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.

    Commentaire
    Si 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); })(); //      } } obj.test(); //  ,     obj.   

    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!

Source: https://habr.com/ru/post/fr464163/


All Articles