J'ai une fonction constructeur qui enregistre un gestionnaire d'événements:
function MyConstructor(data, transport) {
this.data = data;
transport.on('data', function () {
alert(this.data);
});
}
// Mock transport object
var transport = {
on: function(event, callback) {
setTimeout(callback, 1000);
}
};
// called as
var obj = new MyConstructor('foo', transport);
Cependant, je ne suis pas en mesure d'accéder à la data
propriété de l'objet créé à l'intérieur du rappel. Il semble que this
cela ne se réfère pas à l'objet qui a été créé mais à un autre.
J'ai également essayé d'utiliser une méthode objet au lieu d'une fonction anonyme:
function MyConstructor(data, transport) {
this.data = data;
transport.on('data', this.alert);
}
MyConstructor.prototype.alert = function() {
alert(this.name);
};
mais il présente les mêmes problèmes.
Comment puis-je accéder au bon objet?
javascript
callback
this
Felix Kling
la source
la source
Réponses:
Ce que vous devez savoir
this
this
(aka "le contexte") est un mot-clé spécial à l'intérieur de chaque fonction et sa valeur ne dépend que de la façon dont la fonction a été appelée, et non de la manière / quand / où elle a été définie. Il n'est pas affecté par les portées lexicales comme les autres variables (à l'exception des fonctions fléchées, voir ci-dessous). Voici quelques exemples:Pour en savoir plus
this
, consultez la documentation MDN .Comment se référer à la bonne
this
Ne pas utiliser
this
En fait, vous ne voulez pas accéder
this
en particulier, mais à l'objet auquel il se réfère . C'est pourquoi une solution simple consiste à créer simplement une nouvelle variable qui fait également référence à cet objet. La variable peut avoir n'importe quel nom, mais les plus courants sontself
etthat
.Étant donné qu'il
self
s'agit d'une variable normale, elle obéit aux règles de portée lexicale et est accessible à l'intérieur du rappel. Cela a également l'avantage que vous pouvez accéder à lathis
valeur du rappel lui-même.Ensemble explicite
this
du rappel - partie 1Il peut sembler que vous n'avez aucun contrôle sur la valeur de
this
car sa valeur est définie automatiquement, mais ce n'est en fait pas le cas.Chaque fonction a la méthode
.bind
[docs] , qui retourne une nouvelle fonctionthis
liée à une valeur. La fonction a exactement le même comportement que celui que vous avez appelé.bind
, seulement celui quethis
vous avez défini. Peu importe comment ou quand cette fonction est appelée, ellethis
fera toujours référence à la valeur transmise.Dans ce cas, nous à lier de la fonction de rappel
this
à la valeur deMyConstructor
« sthis
.Remarque: lors de la liaison du contexte pour jQuery, utilisez plutôt
jQuery.proxy
[docs] . La raison pour cela est que vous n'avez pas besoin de stocker la référence à la fonction lors de la dissociation d'un rappel d'événement. jQuery gère cela en interne.ECMAScript 6: Utiliser les fonctions fléchées
ECMAScript 6 introduit les fonctions flèches , qui peuvent être considérées comme des fonctions lambda. Ils n'ont pas leur propre
this
reliure. Au lieu de cela,this
est recherché dans la portée comme une variable normale. Cela signifie que vous n'avez pas à appeler.bind
. Ce n'est pas le seul comportement spécial qu'ils ont, veuillez vous référer à la documentation MDN pour plus d'informations.Ensemble
this
du rappel - partie 2Certaines fonctions / méthodes qui acceptent les rappels acceptent également une valeur à laquelle les rappels
this
doivent se référer. C'est fondamentalement la même chose que de le lier vous-même, mais la fonction / méthode le fait pour vous.Array#map
[docs] est une telle méthode. Sa signature est:Le premier argument est le rappel et le deuxième argument est la valeur à laquelle il
this
faut se référer. Voici un exemple artificiel:Remarque: La possibilité de transmettre ou non une valeur pour
this
est généralement mentionnée dans la documentation de cette fonction / méthode. Par exemple, la$.ajax
méthode de jQuery [docs] décrit une option appeléecontext
:Problème courant: utilisation de méthodes d'objet comme rappels / gestionnaires d'événements
Une autre manifestation courante de ce problème est lorsqu'une méthode objet est utilisée comme gestionnaire de rappel / événement. Les fonctions sont des citoyens de première classe en JavaScript et le terme "méthode" n'est qu'un terme familier pour une fonction qui est une valeur d'une propriété d'objet. Mais cette fonction n'a pas de lien spécifique vers son objet "contenant".
Prenons l'exemple suivant:
La fonction
this.method
est affectée en tant que gestionnaire d'événements click, mais si l'document.body
on clique sur, la valeur consignée seraundefined
, car à l'intérieur du gestionnaire d'événements,this
fait référence àdocument.body
, pas à l'instance deFoo
.Comme déjà mentionné au début, ce qui
this
fait référence dépend de la façon dont la fonction est appelée , et non de la façon dont elle est définie .Si le code était le suivant, il pourrait être plus évident que la fonction n'a pas de référence implicite à l'objet:
La solution est la même que celle mentionnée ci-dessus: si disponible, utilisez
.bind
pour lier explicitementthis
à une valeur spécifiqueou appeler explicitement la fonction en tant que "méthode" de l'objet, en utilisant une fonction anonyme comme gestionnaire de rappel / événement et attribuer l'objet (
this
) à une autre variable:ou utilisez une fonction flèche:
la source
self
et auxquelsthat
se référerthis
. Je ressens cela parce quethis
c'est une variable surchargée utilisée dans différents contextes; alors queself
correspond généralement à l'instance locale etthat
fait généralement référence à un autre objet. Je sais que vous n'avez pas établi cette règle, comme je l'ai vu apparaître dans un certain nombre d'autres endroits, mais c'est aussi pourquoi j'ai commencé à l'utiliser_this
, mais je ne sais pas comment les autres se sentent, sauf pour la pratique non uniforme qui en a résulté.Function.prototype.call ()
etFunction.prototype.apply ()
. Surtout avecapply ()
j'ai beaucoup de kilométrage. Je suis moins enclin à utiliserbind ()
peut-être seulement par habitude, bien que je sois conscient (mais pas certain) qu'il puisse y avoir de légers avantages généraux à utiliser bind par rapport aux autres options.() => this.clicked()
;)Voici plusieurs façons d'accéder au contexte parent dans le contexte enfant -
bind()
fonction.1. Utilisez
bind()
fonctionSi vous utilisez
underscore.js
- http://underscorejs.org/#bind2 Stocker la référence au contexte / ceci dans une autre variable
3 Fonction flèche
la source
Tout est dans la syntaxe "magique" de l'appel d'une méthode:
Lorsque vous obtenez la propriété de l'objet et l'appelez en une seule fois, l'objet sera le contexte de la méthode. Si vous appelez la même méthode, mais dans des étapes distinctes, le contexte est la portée globale (fenêtre) à la place:
Lorsque vous obtenez la référence d'une méthode, elle n'est plus attachée à l'objet, c'est juste une référence à une fonction ordinaire. La même chose se produit lorsque vous obtenez la référence à utiliser comme rappel:
C'est là que vous lieriez le contexte à la fonction:
Si vous utilisez jQuery, vous devez utiliser la
$.proxy
méthode à la place, car ellebind
n'est pas prise en charge dans tous les navigateurs:la source
Le problème avec le "contexte"
Le terme "contexte" est parfois utilisé pour désigner l'objet référencé par celui-ci . Son utilisation est inappropriée car elle ne correspond ni sémantiquement ni techniquement à ECMAScript's this .
«Contexte» signifie les circonstances entourant quelque chose qui ajoute du sens, ou certaines informations précédentes et suivantes qui donnent un sens supplémentaire. Le terme "contexte" est utilisé dans ECMAScript pour faire référence au contexte d'exécution , qui est tous les paramètres, la portée et ce dans la portée de certains codes d'exécution.
Ceci est illustré dans la section 10.4.2 de l'ECMA-262 :
ce qui indique clairement que cette fait partie d'un contexte d'exécution.
Un contexte d'exécution fournit les informations environnantes qui ajoutent du sens au code en cours d'exécution. Il comprend beaucoup plus d'informations que la seule .
Donc, la valeur de ce n'est pas un "contexte", c'est juste une partie d'un contexte d'exécution. C'est essentiellement une variable locale qui peut être définie par l'appel à n'importe quel objet et en mode strict, à n'importe quelle valeur.
la source
this
mais aucun n'est proposé ici, et il est sans doute trop tard pour fermer la porte sur le «contexte».Vous devriez connaître «ce» mot-clé.
Selon moi, vous pouvez implémenter "ceci" de trois manières (fonction Self / Arrow / méthode Bind)
Ce mot-clé d'une fonction se comporte un peu différemment en JavaScript par rapport aux autres langages.
Il présente également quelques différences entre le mode strict et le mode non strict.
Dans la plupart des cas, la valeur de ceci est déterminée par la façon dont une fonction est appelée.
Il ne peut pas être défini par affectation lors de l'exécution et il peut être différent à chaque appel de la fonction.
ES5 a introduit la méthode bind () pour définir la valeur d'une fonction indépendamment de la façon dont elle est appelée,
et ES2015 a introduit des fonctions fléchées qui ne fournissent pas leur propre liaison (il conserve la valeur this du contexte lexical englobant).
Méthode 1: le Soi - Le Soi est utilisé pour maintenir une référence à l'original même si le contexte change. C'est une technique souvent utilisée dans les gestionnaires d'événements (en particulier dans les fermetures).
Référence : https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/this
Méthode 2 : fonction flèche - Une expression de fonction flèche est une alternative syntaxiquement compacte à une expression de fonction régulière,
bien que sans ses propres liaisons avec les mots-clés this, arguments, super ou new.target.
Les expressions de fonction de flèche ne conviennent pas comme méthodes et ne peuvent pas être utilisées comme constructeurs.
Référence : https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions
Méthode 3 : Bind - La méthode bind () crée une nouvelle fonction qui,
lorsqu'il est appelé, son mot clé a la valeur fournie,
avec une séquence d'arguments donnée précédant celle fournie lors de l'appel de la nouvelle fonction.
Référence: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_objects/Function/bind
la source
Tout d'abord, vous devez avoir une compréhension claire
scope
et un comportement desthis
mots clés dans le contexte descope
.this
&scope
:en bref, la portée globale fait référence à l'objet fenêtre.Les variables déclarées dans une portée globale sont accessibles de n'importe où.En revanche, la portée de la fonction réside à l'intérieur d'une fonction.
this
Le mot-clé de portée globale fait référence à l'objet window.this
La fonction inside fait également référence à l'objet window.Alorsthis
fera toujours référence à la fenêtre jusqu'à ce que nous trouvions un moyen de manipulerthis
pour indiquer un contexte de notre choix.Différentes façons de manipuler
this
les fonctions de rappel internes:Ici, j'ai une fonction constructeur appelée Person. Il possède une propriété appelée
name
et quatre méthode appeléesayNameVersion1
,sayNameVersion2
,sayNameVersion3
,sayNameVersion4
. Tous les quatre ont une tâche spécifique.Accepter un rappel et l'invoquer.Le rappel a une tâche spécifique qui consiste à consigner la propriété name d'une instance de la fonction constructeur Person.Créons maintenant une instance à partir du constructeur de personne et invoquons différentes versions de la
sayNameVersionX
méthode (X fait référence à 1,2,3,4) avecniceCallback
pour voir de combien de façons nous pouvons manipuler lethis
rappel interne pour faire référence à l'person
instance.lier :
La fonction de liaison consiste à créer une nouvelle fonction avec le
this
mot clé défini sur la valeur fournie.sayNameVersion1
etsayNameVersion2
utilisez bind pour manipulerthis
la fonction de rappel.le premier
this
est lié avec un rappel à l'intérieur de la méthode elle-même, et pour le second, un rappel est passé avec l'objet qui lui est lié.appel :
Le
first argument
de lacall
méthode est utilisé commethis
à l'intérieur de la fonction qui est invoquée aveccall
attaché à elle.sayNameVersion3
utilisecall
pour manipuler lethis
pour faire référence à l'objet personne que nous avons créé, au lieu de l'objet fenêtre.et il est appelé comme suit:
appliquer :
Similaire à
call
, le premier argument deapply
fait référence à l'objet qui sera indiqué parthis
mot-clé.sayNameVersion4
utiliseapply
pour manipulerthis
pour faire référence à un objet personneet il est appelé comme suit. Simplement le rappel est passé,
la source
Nous ne pouvons pas le lier à
setTimeout()
, car il s'exécute toujours avec un objet global (Window) , si vous voulez accéder authis
contexte dans la fonction de rappel, alors en utilisantbind()
la fonction de rappel, nous pouvons obtenir:la source
La question tourne autour de la façon dont les
this
mots clés se comportent en javascript.this
se comporte différemment comme ci-dessous,this
est généralement déterminée par un contexte d'exécution de fonctions.this
fait référence à l'objet global (l'window
objet).this
seraundefined
comme en mode strict, l'objet global fait référence à laundefined
place duwindow
objet.call()
,bind()
etapply()
new
mot clé est utilisé (un constructeur), il est lié au nouvel objet en cours de création.this
- au lieu de cela,this
sont reliées lexicalement (c'est-à-dire basées sur le contexte d'origine)Comme la plupart des réponses le suggèrent, nous pouvons utiliser la fonction Flèche ou
bind()
Méthode ou Auto var. Je voudrais citer un point sur les lambdas (fonction flèche) du guide de style Google JavaScriptGoogle recommande clairement d'utiliser des lambdas plutôt que de lier ou
const self = this
Donc, la meilleure solution serait d'utiliser des lambdas comme ci-dessous,
Références:
la source
this
mots clés, c'est pourquoi j'ai divisé ma réponse en deux parties, une surthis
et une sur l'utilisation des fonctions / méthodes en tant que rappels. N'hésitez pas à modifier la réponse.Actuellement, il existe une autre approche possible si les classes sont utilisées dans le code.
Avec la prise en charge des champs de classe, il est possible de procéder de la manière suivante:
Bien sûr, sous le capot, ce sont toutes les bonnes fonctions de flèche qui lient le contexte, mais sous cette forme, cela semble beaucoup plus clair que la liaison explicite.
Comme il s'agit de la proposition de l'étape 3, vous aurez besoin de babel et du plugin babel approprié pour le traiter comme pour le moment (08/2018).
la source
public methodName = (params) => { body }
intérieur d'une classe.Une autre approche, qui est la façon standard depuis DOM2 de se lier
this
au sein de l'écouteur d'événements, qui vous permet de toujours supprimer l'écouteur (entre autres avantages), est lahandleEvent(evt)
méthode de l'EventListener
interface:Des informations détaillées sur l'utilisation
handleEvent
peuvent être trouvées ici: https://medium.com/@WebReflection/dom-handleevent-a-cross-platform-standard-since-year-2000-5bf17287fd38la source
this
dans JS:La valeur de
this
dans JS est déterminée à 100% par la façon dont une fonction est appelée et non par la façon dont elle est définie. Nous pouvons relativement facilement trouver la valeur dethis
par la «gauche de la règle des points» :this
est l'objet à gauche du point de la fonction qui est appeléethis
intérieur d'une fonction est souvent l'objet global (global
dans le nœud,window
dans le navigateur). Je ne recommanderais pas d'utiliser lethis
mot - clé ici car il est moins explicite que d'utiliser quelque chose commewindow
!Function.prototype.bind()
fonction qui peut fixer la valeur dethis
. Ce sont des exceptions à la règle, mais elles sont vraiment utiles pour fixer la valeur dethis
.Exemple dans nodeJS
Production:
Permettez-moi de vous guider à travers les sorties 1 par 1 (en ignorant le premier journal à partir du second):
this
est àobj2
cause de la gauche de la règle des points, nous pouvons voir commenttest1
est appeléobj2.test1();
.obj2
est à gauche du point et donc de lathis
valeur.obj2
est à gauche du point,test2
est lié àobj1
via labind()
méthode. Lathis
valeur est doncobj1
.obj2
est à gauche du point de la fonction qui est appelée:obj2.test3()
. Par conséquentobj2
, la valeur dethis
.obj2.test4()
obj2
est à gauche du point. Cependant, la fonction flèche n'a pas sa proprethis
liaison. Par conséquent, il se liera à lathis
valeur de la portée externe qui est l'module.exports
objet qui a été enregistré au début.this
en utilisant lacall
fonction. Ici, nous pouvons passer lathis
valeur souhaitée comme argument, ce qui est leobj2
cas dans ce cas.la source