Question

J'ai quelques problèmes avec le vieux code JavaScript (pas de framework) pour référencer mon objet dans une fonction de rappel.

function foo(id) {
    this.dom = document.getElementById(id);
    this.bar = 5;
    var self = this;
    this.dom.addEventListener("click", self.onclick, false);
}

foo.prototype = {
    onclick : function() {
        this.bar = 7;
    }
};

Maintenant, lorsque je crée un nouvel objet (après le chargement du DOM, avec un span # test)

var x = new foo('test');

Le "ceci" dans la fonction onclick pointe vers le test # span et non vers l'objet foo.

Comment obtenir une référence à mon objet foo dans la fonction onclick?

Était-ce utile?

La solution

(extrait une explication masquée dans les commentaires d'une autre réponse)

Le problème réside dans la ligne suivante:

this.dom.addEventListener("click", self.onclick, false);

Ici, vous passez un objet fonction à utiliser comme rappel. Lorsque l'événement se déclenche, la fonction est appelée mais à présent, elle n'est associée à aucun objet (this).

Le problème peut être résolu en encapsulant la fonction (avec sa référence d'objet) dans une fermeture comme suit:

this.dom.addEventListener(
  "click",
  function(event) {self.onclick(event)},
  false);

Etant donné que la variable self a été assignée this lors de la création de la fermeture, la fonction de fermeture mémorisera la valeur de la variable self lorsqu’elle sera appelée ultérieurement.

Une autre solution consiste à créer une fonction d’utilité (et à éviter d’utiliser des variables pour lier this ):

function bind(scope, fn) {
    return function () {
        fn.apply(scope, arguments);
    };
}

Le code mis à jour ressemblerait alors à:

this.dom.addEventListener("click", bind(this, this.onclick), false);

Function.prototype.bind a> fait partie de ECMAScript 5 et fournit les mêmes fonctionnalités. Donc vous pouvez faire:

this.dom.addEventListener("click", this.onclick.bind(this), false);

Pour les navigateurs ne prenant pas encore ES5 en charge, MDN fournit le shim suivant. :

if (!Function.prototype.bind) {  
  Function.prototype.bind = function (oThis) {  
    if (typeof this !== "function") {  
      // closest thing possible to the ECMAScript 5 internal IsCallable function  
      throw new TypeError("Function.prototype.bind - what is trying to be bound is not callable");  
    }  

    var aArgs = Array.prototype.slice.call(arguments, 1),   
        fToBind = this,   
        fNOP = function () {},  
        fBound = function () {  
          return fToBind.apply(this instanceof fNOP  
                                 ? this  
                                 : oThis || window,  
                               aArgs.concat(Array.prototype.slice.call(arguments)));  
        };  

    fNOP.prototype = this.prototype;  
    fBound.prototype = new fNOP();  

    return fBound;  
  };  
} 

Autres conseils

this.dom.addEventListener("click", function(event) {
    self.onclick(event)
}, false);

Pour les utilisateurs de jQuery à la recherche d'une solution à ce problème, vous devez utiliser jQuery.proxy

L'explication est que self.onclick ne signifie pas ce que vous pensez que cela signifie en JavaScript. Cela signifie en fait que la fonction onclick du prototype de l'objet self (sans se référant de toute façon à self ).

JavaScript n'a que des fonctions et aucun délégué comme C #, il n'est donc pas possible de transmettre une méthode ET l'objet auquel elle doit être appliquée en tant que rappel.

Le seul moyen d'appeler une méthode dans un rappel est de l'appeler vous-même dans une fonction de rappel. Les fonctions JavaScript étant des fermetures, elles peuvent accéder aux variables déclarées dans l'étendue dans laquelle elles ont été créées.

var obj = ...;
function callback(){ return obj.method() };
something.bind(callback);

Une bonne explication du problème (j'ai eu du mal à comprendre les solutions décrites jusqu'à présent) est disponible ici .

J'ai écrit ce plugin ...

Je pense que ce sera utile

jquery.callback

C’est l’un des points les plus déroutants de JS: la variable "this" signifie pour l’objet le plus local ... mais les fonctions sont aussi des objets, donc "ceci" y pointe. Il y a d'autres points subtils, mais je ne me souviens pas de tous.

J'évite généralement d'utiliser 'this', définissez simplement une variable 'me' locale et utilisez-la plutôt.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top