Cet article couvre un sujet avancé pour mieux comprendre certains cas limites.
Ce nâest pas important. De nombreux développeurs expérimentés vivent bien sans le savoir. Continuez à lire si vous voulez savoir comment les choses fonctionnent sous le capot.
Un appel de méthode évalué dynamiquement peut perdre this.
Par exemple:
let user = {
name: "John",
hi() { alert(this.name); },
bye() { alert("Bye"); }
};
user.hi(); // fonctionne
// essayons maintenant d'appeler user.hi ou user.by selon name
(user.name == "John" ? user.hi : user.bye)(); // Error !
Sur la dernière ligne il y a un opérateur conditionnel qui choisit entre user.hi ou user.bye. Ici le résultat est user.hi.
Ensuite la méthode est immédiatement appelée avec les parenthèses (). Mais cela ne fonctionne pas !
Comme vous pouvez le voir, lâappel se résout avec une erreur car la valeur de "this" dans lâappel devient undefined.
Cet appel fonctionne (syntaxe de notation par points):
user.hi();
Celui-là non (méthode évaluée):
(user.name == "John" ? user.hi : user.bye)(); // Error !
Pourquoi ? Si nous voulons comprendre pourquoi cela arrive, regardons comment lâappel de obj.method() fonctionne sous le capot.
Le type référence expliqué
En y regardant plus précisement, on peut remarquer 2 opérations dans la déclaration de obj.method():
- En premier, le point
'.'récupère la propriétéobj.method. - Puis les parenthèses
()lâéxécute.
Mais comment lâinformation du this est passée de la première opération à la deuxième ?
Si on sépare ces opération sur 2 lignes, alors this sera perdu :
let user = {
name: "John",
hi() { alert(this.name); }
};
// On sépare l'accès à la méthode et son appel en deux lignes
let hi = user.hi;
hi(); // Error, car this n'est pas définit
Ici hi = user.hi assigne la fonction à la variable, ensuite sur la dernière ligne this est complétement autonome et donc il nây a pas de this.
Pour faire que user.hi() fonctionne, JavaScript utilise une astuce â le point '.' ne retourne pas une fonction, mais une valeur de type référence.
Le type référence nâest pas un âtype de spécifiationâ. On ne peut lâutiliser explicitement, mais il est utilisé en interne par le langage.
La valeur de Type Référence est une combinaison de 3 valeurs (base, name, strict), où :
baseest lâobjet.nameest le nom de la propriété.strictest vrai siuse strictest en vigueur.
Le résultat de lâaccès à la propriété user.hi nâest pas une fonction, mais une valeur de Type Référence. Pour user.hi en mode strict cela est :
// Valeur de type référence
(user, "hi", true)
Lorsque les parenthèses () sont appelées sur le type de référence, elles reçoivent les informations complètes sur lâobjet et sa méthode, et peuvent définir le bon this (user dans ce cas).
Le type référence est un type interne âintermédiaireâ, avec comme but de passer lâinformation du point . aux parenthèses ().
Nâimporte quelle autre opération dâassignement comme hi = user.hi rejette le type référence, prends la valeur de user.hi (une fonction) et la passe. Ainsi nâimporte quelle opération suivante âperdâ this.
Il en résulte que la valeur de this nâest passée correctement seulement lorsque la fonction est appelée directement en utilisant la notation par points obj.method() ou la notation par crochet obj['method']() (câest la même chose). Il existe différentes manières de résoudre ce problème comme func.bind().
Résumé
Le type référence est un type interne au langage.
En lisant une propriété, comme avec le point . dans obj.method(), qui ne retourne pas la valeur de la propriété mais la valeur spéciale de âtype référenceâ, qui garde le nom de la propriété et lâobjet relié à la propriété.
Thatâs for the subsequent method call () to get the object and set this to it.
Cela est fait pour que lâéxécution suivante, lâappel à la méthode (), reçoive lâobjet et lui assigne this.
Pour toutes les autres opérations, le type référence sera automatiquement la valeur de la propriété (une fonction dans notre cas).
Le fonctionnement est caché de notre vision. Cela nâa dâimportance que dans certains cas, comme lorsquâune méthode est obtenue dynamiquement de lâobject en utilisant une expression.
Commentaires
<code>, pour plusieurs lignes â enveloppez-les avec la balise<pre>, pour plus de 10 lignes - utilisez une sandbox (plnkr, jsbin, codepenâ¦)