Domanda

Ho dei problemi con il semplice vecchio JavaScript (senza framework) nel fare riferimento al mio oggetto in una funzione di callback.

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;
    }
};

Ora quando creo un nuovo oggetto (dopo che il DOM è stato caricato, con un span # test)

var x = new foo('test');

Il 'this' all'interno della funzione onclick punta allo span # test e non all'oggetto foo.

Come posso ottenere un riferimento al mio oggetto foo all'interno della funzione onclick?

È stato utile?

Soluzione

(ha estratto alcune spiegazioni che erano nascoste nei commenti in altre risposte)

Il problema si trova nella seguente riga:

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

Qui, si passa un oggetto funzione da utilizzare come callback. Quando si attiva l'evento, la funzione viene chiamata ma ora non ha alcuna associazione con nessun oggetto (questo).

Il problema può essere risolto avvolgendo la funzione (con il riferimento all'oggetto) in una chiusura come segue:

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

Dato che alla variabile self è stato assegnato this quando è stata creata la chiusura, la funzione di chiusura ricorderà il valore della variabile self quando viene chiamata in un secondo momento.

Un modo alternativo per risolvere questo è quello di far funzionare una utility (ed evitare di usare le variabili per legare this ):

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

Il codice aggiornato sarebbe quindi:

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

Function.prototype.bind fa parte di ECMAScript 5 e fornisce la stessa funzionalità. Quindi puoi fare:

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

Per i browser che non supportano ancora ES5, MDN fornisce il seguente spessore :

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;  
  };  
} 

Altri suggerimenti

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

Per gli utenti jQuery che cercano una soluzione a questo problema, dovresti utilizzare jQuery.proxy

La spiegazione è che self.onclick non significa cosa pensi che significhi in JavaScript. In realtà significa la funzione onclick nel prototipo dell'oggetto self (senza fare riferimento in alcun modo a self ).

JavaScript ha solo funzioni e nessun delegato come C #, quindi non è possibile passare un metodo E l'oggetto a cui dovrebbe essere applicato come callback.

L'unico modo per chiamare un metodo in un callback è chiamarlo da soli all'interno di una funzione di callback. Poiché le funzioni JavaScript sono chiusure, sono in grado di accedere alle variabili dichiarate nell'ambito in cui sono state create.

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

Una buona spiegazione del problema (ho avuto problemi a comprendere le soluzioni descritte finora) è disponibile qui .

Ho scritto questo plugin ...

Penso che sarà utile

jquery.callback

questo è uno dei punti più confusi di JS: la variabile 'this' significa per l'oggetto più locale ... ma le funzioni sono anche oggetti, quindi 'this' punta lì. Ci sono altri punti sottili, ma non li ricordo tutti.

Di solito evito di usare 'this', semplicemente definisco una variabile 'me' locale e la uso invece.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top