Comment accéder au bon «ceci» dans un rappel?

1425

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 datapropriété de l'objet créé à l'intérieur du rappel. Il semble que thiscela 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?

Felix Kling
la source
95
De temps en temps, j'en ai tellement marre d'un certain type de question, que je décide d'écrire une réponse canonique. Même si ces questions ont été répondues comme un million de fois, il n'est pas toujours possible de trouver une bonne paire question + réponse qui ne soit pas «polluée» par des informations non pertinentes. C'est l'un de ces moments et l'une de ces questions (et je m'ennuie). Si vous pensez qu'il existe en fait une bonne question / réponse canonique pour ce type de question, faites-le moi savoir et je supprimerai celle-ci. Les suggestions d'améliorations sont les bienvenues!
Felix Kling
3
Page TypeScript utile à ce sujet , également applicable à JS.
Ondra Žižka

Réponses:

1791

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:

function foo() {
    console.log(this);
}

// normal function call
foo(); // `this` will refer to `window`

// as object method
var obj = {bar: foo};
obj.bar(); // `this` will refer to `obj`

// as constructor function
new foo(); // `this` will refer to an object that inherits from `foo.prototype`

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 thisen 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 sont selfet that.

function MyConstructor(data, transport) {
    this.data = data;
    var self = this;
    transport.on('data', function() {
        alert(self.data);
    });
}

Étant donné qu'il selfs'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 à la thisvaleur du rappel lui-même.

Ensemble explicite thisdu rappel - partie 1

Il peut sembler que vous n'avez aucun contrôle sur la valeur de thiscar 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 fonction thisliée à une valeur. La fonction a exactement le même comportement que celui que vous avez appelé .bind, seulement celui que thisvous avez défini. Peu importe comment ou quand cette fonction est appelée, elle thisfera toujours référence à la valeur transmise.

function MyConstructor(data, transport) {
    this.data = data;
    var boundFunction = (function() { // parenthesis are not necessary
        alert(this.data);             // but might improve readability
    }).bind(this); // <- here we are calling `.bind()` 
    transport.on('data', boundFunction);
}

Dans ce cas, nous à lier de la fonction de rappel thisà la valeur de MyConstructor« s this.

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 thisreliure. Au lieu de cela, thisest 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.

function MyConstructor(data, transport) {
    this.data = data;
    transport.on('data', () => alert(this.data));
}

Ensemble thisdu rappel - partie 2

Certaines fonctions / méthodes qui acceptent les rappels acceptent également une valeur à laquelle les rappels thisdoivent 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:

array.map(callback[, thisArg])

Le premier argument est le rappel et le deuxième argument est la valeur à laquelle il thisfaut se référer. Voici un exemple artificiel:

var arr = [1, 2, 3];
var obj = {multiplier: 42};

var new_arr = arr.map(function(v) {
    return v * this.multiplier;
}, obj); // <- here we are passing `obj` as second argument

Remarque: La possibilité de transmettre ou non une valeur pour thisest généralement mentionnée dans la documentation de cette fonction / méthode. Par exemple, la $.ajaxméthode de jQuery [docs] décrit une option appelée context:

Cet objet deviendra le contexte de tous les rappels liés à Ajax.


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:

function Foo() {
    this.data = 42,
    document.body.onclick = this.method;
}

Foo.prototype.method = function() {
    console.log(this.data);
};

La fonction this.methodest affectée en tant que gestionnaire d'événements click, mais si l' document.bodyon clique sur, la valeur consignée sera undefined, car à l'intérieur du gestionnaire d'événements, thisfait référence à document.body, pas à l'instance de Foo.
Comme déjà mentionné au début, ce qui thisfait 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:

function method() {
    console.log(this.data);
}


function Foo() {
    this.data = 42,
    document.body.onclick = this.method;
}

Foo.prototype.method = method;

La solution est la même que celle mentionnée ci-dessus: si disponible, utilisez .bindpour lier explicitementthis à une valeur spécifique

document.body.onclick = this.method.bind(this);

ou 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:

var self = this;
document.body.onclick = function() {
    self.method();
};

ou utilisez une fonction flèche:

document.body.onclick = () => this.method();
Felix Kling
la source
39
Félix, j'ai déjà lu cette réponse mais je n'ai jamais répondu. Je m'inquiète de plus en plus que les gens utilisent selfet auxquels thatse référer this. Je ressens cela parce que thisc'est une variable surchargée utilisée dans différents contextes; alors que selfcorrespond généralement à l'instance locale et thatfait 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é.
vol7ron
3
@FelixKling serait-il prudent de supposer que l'utilisation de ces fonctions prototypes internes aura toujours le comportement attendu, quelle que soit la façon dont elles sont (généralement) appelées? Lors de l'utilisation de rappels à l'intérieur de fonctions de prototype, existe-t-il une alternative à bind (), self ou ça?
andig
5
@FelixKling Il peut parfois être utile de s'appuyer sur Function.prototype.call ()et Function.prototype.apply (). Surtout avec apply ()j'ai beaucoup de kilométrage. Je suis moins enclin à utiliser bind ()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.
Nolo
5
Excellente réponse, mais pensez à ajouter une solution facultative supplémentaire qui consiste simplement à ne pas utiliser de classes, nouvelles ou tout cela.
Aluan Haddad du
4
re arrow functions "Au lieu de cela, cela est recherché dans la portée comme une variable normale." totalement fait ce clic pour moi, merci! () => this.clicked();)
alphanumeric0101
211

Voici plusieurs façons d'accéder au contexte parent dans le contexte enfant -

  1. Vous pouvez utiliser la bind()fonction.
  2. Stockez la référence au contexte / ceci dans une autre variable (voir l'exemple ci-dessous).
  3. Utilisez les fonctions fléchées ES6 .
  4. Modifier le code / la conception / l'architecture des fonctions - pour cela, vous devez avoir la commande les modèles de conception en javascript.

1. Utilisez bind() fonction

function MyConstructor(data, transport) {
    this.data = data;
    transport.on('data', ( function () {
        alert(this.data);
    }).bind(this) );
}
// Mock transport object
var transport = {
    on: function(event, callback) {
        setTimeout(callback, 1000);
    }
};
// called as
var obj = new MyConstructor('foo', transport);

Si vous utilisez underscore.js- http://underscorejs.org/#bind

transport.on('data', _.bind(function () {
    alert(this.data);
}, this));

2 Stocker la référence au contexte / ceci dans une autre variable

function MyConstructor(data, transport) {
  var self = this;
  this.data = data;
  transport.on('data', function() {
    alert(self.data);
  });
}

3 Fonction flèche

function MyConstructor(data, transport) {
  this.data = data;
  transport.on('data', () => {
    alert(this.data);
  });
}
Mohan Dere
la source
1
L'option bind () est incroyable, elle passe juste le pointeur de cet objet pour être celui-ci sur l'autre objet (: Merci!
Stav Bodik
Le bind () fonctionne comme un charme. Merci beaucoup +1 de ma part :)
Anjana Silva
56

Tout est dans la syntaxe "magique" de l'appel d'une méthode:

object.property();

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:

var f = object.property;
f();

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:

this.saveNextLevelData(this.setAll);

C'est là que vous lieriez le contexte à la fonction:

this.saveNextLevelData(this.setAll.bind(this));

Si vous utilisez jQuery, vous devez utiliser la $.proxyméthode à la place, car elle bindn'est pas prise en charge dans tous les navigateurs:

this.saveNextLevelData($.proxy(this.setAll, this));
Guffa
la source
33

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 :

Définissez ThisBinding sur la même valeur que ThisBinding du contexte d'exécution appelant

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.

RobG
la source
Je ne suis pas d'accord avec cette réponse. L'existence du terme "contexte d'exécution" n'interdit pas d'autres utilisations de "contexte" pas plus qu'elle n'interdit d'autres utilisations d '"exécution". Peut-être y a-t-il un meilleur terme à décrire thismais aucun n'est proposé ici, et il est sans doute trop tard pour fermer la porte sur le «contexte».
Roamer-1888
@ Roamer-1888 - merci pour la modification. Vous avez raison, mais mon argument ne repose pas sur l'existence d'un "contexte d'exécution" excluant le "contexte" à d'autres fins. Il est plutôt basé sur le fait que le «contexte» est inapproprié d'un point de vue technique et sémantique. Je pense également que l'utilisation de «contexte» au lieu de «ceci» est en train de disparaître. Je ne vois aucune raison de trouver un terme alternatif à ceci ou à cette liaison , cela obscurcit simplement et signifie à un moment donné que vous devez expliquer que le "contexte" est réellement ceci , et qu'il ne l'est de toute façon pas "contexte". :-)
RobG
Je ne pense pas que vous puissiez dire que ce n'est en aucun cas un "contexte", alors que vous avez déjà admis qu'il s'agit d'une partie d'un contexte d'exécution, où "l'exécution" n'est qu'un adjectival.
Roamer-1888
@ Roamer-1888 - Je ne vais pas continuer cette conversation au-delà de ce point. Oui, cela fait partie d'un contexte d'exécution. Dire que c'est le contexte, c'est comme dire qu'un joueur d'une équipe est l'équipe.
RobG
RobG, dommage que tu ne veuilles pas continuer. C'est un débat intéressant. Merci de me donner de votre temps.
Roamer-1888
31

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

function MyConstructor(data, transport) {
    this.data = data;
    var self = this;
    transport.on('data', function () {
        alert(self.data);
    });
}

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

  function MyConstructor(data, transport) {
    this.data = data;
    transport.on('data',()=> {
        alert(this.data);
    });
}

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

  function MyConstructor(data, transport) {
    this.data = data;
    transport.on('data',(function() {
        alert(this.data);
    }).bind(this);
Ashish
la source
25

Tout d'abord, vous devez avoir une compréhension claire scopeet un comportement des thismots clés dans le contexte de scope.

this& scope:


there are two types of scope in javascript. They are :

   1) Global Scope

   2) Function 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. thisLe mot-clé de portée globale fait référence à l'objet window. thisLa fonction inside fait également référence à l'objet window.Alors thisfera toujours référence à la fenêtre jusqu'à ce que nous trouvions un moyen de manipuler thispour indiquer un contexte de notre choix.

--------------------------------------------------------------------------------
-                                                                              -
-   Global Scope                                                               -
-   ( globally "this" refers to window object)                                 -     
-                                                                              -
-         function outer_function(callback){                                   -
-                                                                              -
-               // outer function scope                                        -
-               // inside outer function"this" keyword refers to window object -                                                                              -
-              callback() // "this" inside callback also refers window object  -

-         }                                                                    -
-                                                                              -
-         function callback_function(){                                        -
-                                                                              -
-                //  function to be passed as callback                         -
-                                                                              -
-                // here "THIS" refers to window object also                   -
-                                                                              -
-         }                                                                    -
-                                                                              -
-         outer_function(callback_function)                                    -
-         // invoke with callback                                              -
--------------------------------------------------------------------------------

Différentes façons de manipuler thisles fonctions de rappel internes:

Ici, j'ai une fonction constructeur appelée Person. Il possède une propriété appelée nameet quatre méthode appelée sayNameVersion1, 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.

function Person(name){

    this.name = name

    this.sayNameVersion1 = function(callback){
        callback.bind(this)()
    }
    this.sayNameVersion2 = function(callback){
        callback()
    }

    this.sayNameVersion3 = function(callback){
        callback.call(this)
    }

    this.sayNameVersion4 = function(callback){
        callback.apply(this)
    }

}

function niceCallback(){

    // function to be used as callback

    var parentObject = this

    console.log(parentObject)

}

Créons maintenant une instance à partir du constructeur de personne et invoquons différentes versions de la sayNameVersionXméthode (X fait référence à 1,2,3,4) avec niceCallbackpour voir de combien de façons nous pouvons manipuler le thisrappel interne pour faire référence à l' personinstance.

var p1 = new Person('zami') // create an instance of Person constructor

lier :

La fonction de liaison consiste à créer une nouvelle fonction avec le thismot clé défini sur la valeur fournie.

sayNameVersion1et sayNameVersion2utilisez bind pour manipuler thisla fonction de rappel.

this.sayNameVersion1 = function(callback){
    callback.bind(this)()
}
this.sayNameVersion2 = function(callback){
    callback()
}

le premier thisest 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é.

p1.sayNameVersion1(niceCallback) // pass simply the callback and bind happens inside the sayNameVersion1 method

p1.sayNameVersion2(niceCallback.bind(p1)) // uses bind before passing callback

appel :

Le first argumentde la callméthode est utilisé comme thisà l'intérieur de la fonction qui est invoquée avec callattaché à elle.

sayNameVersion3utilise callpour manipuler le thispour faire référence à l'objet personne que nous avons créé, au lieu de l'objet fenêtre.

this.sayNameVersion3 = function(callback){
    callback.call(this)
}

et il est appelé comme suit:

p1.sayNameVersion3(niceCallback)

appliquer :

Similaire à call, le premier argument de applyfait référence à l'objet qui sera indiqué par thismot-clé.

sayNameVersion4utilise applypour manipuler thispour faire référence à un objet personne

this.sayNameVersion4 = function(callback){
    callback.apply(this)
}

et il est appelé comme suit. Simplement le rappel est passé,

p1.sayNameVersion4(niceCallback)
AL-zami
la source
1
toute critique constructive concernant la réponse sera appréciée!
AL-zami
1
Le mot-clé this dans la portée globale ne fait pas nécessairement référence à l' objet window . Cela n'est vrai que dans un navigateur.
Randall Flagg
1
@RandallFlagg j'ai écrit cette réponse du point de vue d'un navigateur.N'hésitez pas à améliorer cette réponse si nécessaire :)
AL-zami
19

Nous ne pouvons pas le lier à setTimeout(), car il s'exécute toujours avec un objet global (Window) , si vous voulez accéder au thiscontexte dans la fonction de rappel, alors en utilisant bind()la fonction de rappel, nous pouvons obtenir:

setTimeout(function(){
    this.methodName();
}.bind(this), 2000);
Datta Chanewad
la source
9
En quoi est-ce différent de l'une des réponses existantes?
Felix Kling
13

La question tourne autour de la façon dont les thismots clés se comportent en javascript. thisse comporte différemment comme ci-dessous,

  1. La valeur de this est généralement déterminée par un contexte d'exécution de fonctions.
  2. Dans la portée globale, thisfait référence à l'objet global (l' windowobjet).
  3. Si le mode strict est activé pour une fonction, la valeur de thissera undefinedcomme en mode strict, l'objet global fait référence à la undefinedplace duwindow objet.
  4. L'objet qui se tient devant le point est ce à quoi le mot-clé this sera lié.
  5. Nous pouvons définir la valeur de cela explicitement avec call(),bind() etapply()
  6. Quand le new mot clé est utilisé (un constructeur), il est lié au nouvel objet en cours de création.
  7. Les fonctions fléchées ne se lient pas this - au lieu de cela, thissont 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 JavaScript

Préférez utiliser les fonctions fléchées sur f.bind (ceci), et surtout sur goog.bind (f, ceci). Évitez d'écrire const self = this. Les fonctions fléchées sont particulièrement utiles pour les rappels, qui passent parfois des arguments supplémentaires inattendus.

Google 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,

function MyConstructor(data, transport) {
  this.data = data;
  transport.on('data', () => {
    alert(this.data);
  });
}

Références:

  1. https://medium.com/tech-tajawal/javascript-this-4-rules-7354abdb274c
  2. flèche-fonctions-vs-bind
Code_Mode
la source
Cette question concerne spécifiquement l'utilisation des fonctions / méthodes en tant que rappels. Votre réponse pourrait être mieux adaptée à stackoverflow.com/q/3127429/218196 .
Felix Kling
@FelixKling Oui, la question concerne l'utilisation des fonctions / méthodes en tant que rappels dans ce problème principal était dû à la gestion des thismots clés, c'est pourquoi j'ai divisé ma réponse en deux parties, une sur thiset une sur l'utilisation des fonctions / méthodes en tant que rappels. N'hésitez pas à modifier la réponse.
Code_Mode
Je trouve votre quatrième point formulé de manière ambiguë. Prenons l' exemple «Problème lors de l'utilisation de méthodes avec cet objet en tant que rappels» , où le bon objet se trouve devant le point, mais le contexte n'est toujours pas cet objet.
bleistift2
7

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:

class someView {
    onSomeInputKeyUp = (event) => {
        console.log(this); // this refers to correct value
    // ....
    someInitMethod() {
        //...
        someInput.addEventListener('input', this.onSomeInputKeyUp)

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

skyboyer
la source
2
C'est exactement la façon dont je l'ai fait fonctionner dans Typescript: à l' public methodName = (params) => { body }intérieur d'une classe.
yeyeyerman
5

Une autre approche, qui est la façon standard depuis DOM2 de se lier thisau sein de l'écouteur d'événements, qui vous permet de toujours supprimer l'écouteur (entre autres avantages), est la handleEvent(evt)méthode de l' EventListenerinterface:

var obj = {
  handleEvent(e) {
    // always true
    console.log(this === obj);
  }
};

document.body.addEventListener('click', obj);

Des informations détaillées sur l'utilisation handleEventpeuvent être trouvées ici: https://medium.com/@WebReflection/dom-handleevent-a-cross-platform-standard-since-year-2000-5bf17287fd38

Andrea Puddu
la source
0

this dans JS:

La valeur de thisdans 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 de thispar la «gauche de la règle des points» :

  1. Lorsque la fonction est créée à l'aide du mot clé function, la valeur de thisest l'objet à gauche du point de la fonction qui est appelée
  2. S'il ne reste aucun objet du point, la valeur de l' thisintérieur d'une fonction est souvent l'objet global ( globaldans le nœud, windowdans le navigateur). Je ne recommanderais pas d'utiliser le thismot - clé ici car il est moins explicite que d'utiliser quelque chose comme window!
  3. Il existe certaines constructions comme les fonctions flèches et les fonctions créées à l'aide de la Function.prototype.bind()fonction qui peut fixer la valeur de this. Ce sont des exceptions à la règle, mais elles sont vraiment utiles pour fixer la valeur de this.

Exemple dans nodeJS

module.exports.data = 'module data';
// This outside a function in node refers to module.exports object
console.log(this);

const obj1 = {
    data: "obj1 data",
    met1: function () {
        console.log(this.data);
    },
    met2: () => {
        console.log(this.data);
    },
};

const obj2 = {
    data: "obj2 data",
    test1: function () {
        console.log(this.data);
    },
    test2: function () {
        console.log(this.data);
    }.bind(obj1),
    test3: obj1.met1,
    test4: obj1.met2,
};

obj2.test1();
obj2.test2();
obj2.test3();
obj2.test4();
obj1.met1.call(obj2);

Production:

entrez la description de l'image ici

Permettez-moi de vous guider à travers les sorties 1 par 1 (en ignorant le premier journal à partir du second):

  1. thisest à obj2cause de la gauche de la règle des points, nous pouvons voir comment test1est appelé obj2.test1();. obj2est à gauche du point et donc de la thisvaleur.
  2. Même s'il obj2est à gauche du point, test2est lié à obj1via la bind()méthode. La thisvaleur est donc obj1.
  3. obj2est à gauche du point de la fonction qui est appelée: obj2.test3(). Par conséquent obj2, la valeur de this.
  4. Dans ce cas: obj2.test4() obj2est à gauche du point. Cependant, la fonction flèche n'a pas sa propre thisliaison. Par conséquent, il se liera à la thisvaleur de la portée externe qui est l' module.exportsobjet qui a été enregistré au début.
  5. Nous pouvons également spécifier la valeur de thisen utilisant la callfonction. Ici, nous pouvons passer la thisvaleur souhaitée comme argument, ce qui est le obj2cas dans ce cas.
Willem van der Veen
la source