2010-05-11 6 views
8

Faccio un po 'di chiamate Ajax dall'interno di un oggetto JavaScript .:XMLHttpRequest all'interno di un oggetto: come mantenere il riferimento a "questo"

myObject.prototye = { 
    ajax: function() { 
    this.foo = 1; 

    var req = new XMLHttpRequest(); 
    req.open('GET', url, true); 
    req.onreadystatechange = function (aEvt) { 
     if (req.readyState == 4) { 
     if(req.status == 200) { 
      alert(this.foo); // reference to this is lost 
     } 
     } 
    } 
}; 

All'interno della funzione onreadystatechange, questo non si riferisce all'oggetto principale più , quindi non ho accesso a questo.foo. Posso mantenere il riferimento all'oggetto principale all'interno degli eventi XMLHttpRequest?

risposta

7

L'approccio più semplice è di solito per memorizzare il valore di this su una variabile locale:

myObject.prototype = { 
    ajax: function (url) { // (url argument missing ?) 
    var instance = this; // <-- store reference to the `this` value 
    this.foo = 1; 

    var req = new XMLHttpRequest(); 
    req.open('GET', url, true); 
    req.onreadystatechange = function (aEvt) { 
     if (req.readyState == 4) { 
     if (req.status == 200) { 
      alert(instance.foo); // <-- use the reference 
     } 
     } 
    }; 
    } 
}; 

Sospetto anche che il vostro identificatore myObject è davvero un constructor function (si sta assegnando una proprietà prototype).

Se questo è il caso, non dimenticare di includere la proprietà constructor corretta (poiché si sta sostituendo l'intero prototype), che è semplicemente un riferimento al costruttore.

Forse off-topic a questo problema, ma raccomanda di leggere:

4

Un'altra soluzione semplice è quella di legare la vostra funzione onreadystatechange a questo. bind -ing la funzione fa essenzialmente la stessa cosa nella risposta di CMS (ovvero, aggiungendo il valore alla chiusura), ma bind lo fa in modo trasparente: si continua a utilizzare this invece di impostare una variabile instance.

Ecco un'implementazione Function#bind se il vostro codice di base non include uno:

Function.prototype.bind = function(obj) { 
    var __method = this; 
    var args = []; for(var i=1; i<arguments.length; i++) args.push(arguments[i]); 
    return function() { 
     var args2 = []; for(var i=0; i<arguments.length; i++) args2.push(arguments[i]); 
     return __method.apply(obj, args.concat(args2)); 
    }; 
} 

Ed ecco come si può utilizzare nel codice:

myObject.prototype = { 
    ajax: function() { 
    this.foo = 1; 

    var req = new XMLHttpRequest(); 
    req.open('GET', url, true); 
    req.onreadystatechange = function (aEvt) { 
     if (req.readyState == 4) { 
     if(req.status == 200) { 
      alert(this.foo); // reference to this is *kept* 
     } 
     } 
    }.bind(this) // <- only change 
    } 
}; 
+0

consiglio vivamente di controllare se il metodo 'Function.prototype.bind' esiste prima di crearlo, poiché fa parte dello standard ECMAScript 5th Edition e viene implementato da tutti i principali fornitori di browser, presto sarà disponibile un'implementazione nativa e non si desidera sostituiscilo con il tuo: [WebKit] (https: // bugs.webkit.org/show_bug.cgi?id=26382), [Mozilla] (https://bugzilla.mozilla.org/show_bug.cgi?id=429507), [Google V8] (http://code.google .com/p/V8/temi/dettaglio? id = 384). – CMS

Problemi correlati