2012-09-06 13 views
11

Sto tentando di fare in modo che un oggetto javascript esegua un metodo differito e quando è .done() chiama una funzione nello stesso oggetto. Sto avendo problemi perché "questo" diventa l'oggetto posticipato anziché l'oggetto che lo ha chiamato.JQuery differito cambia "questo"

PageObject.prototype.successFunction = function() { 
    console.log(arguments); 
    return console.log(this.name + " Success function called"); 
}; 

PageObject.prototype.loadPage = function(url) { 
    return $.when($.mobile.loadPage("pages/" + url)) 
    .done(this.successFunction); 
}; 

var pg = new PageObject(); 
pg.loadPage("test.html"); 

Come si invia "questo" in SuccessFunction? Questo PageObject sarà esteso anche da altri, quindi sapere "questo" quando si esegue SuccessFunction sarà molto utile.

Sembra semplice e probabilmente ha una risposta semplice. Stavo esaminando .apply() ma non sono sicuro che ci abbia aiutato. Questo post sull'overflow dello stack è stato utile un po ', ma si è rotto nel momento in cui l'ho inserito nella funzione .done().

Functions as parameters (with parameters) -- JavaScript

+1

FWIW, l'oggetto posticipato non sta cambiando questo, è solo il modo in cui funzionano le funzioni. Il valore di questo non è determinato da come/dove è definita una funzione, ma da come viene chiamata. –

risposta

14

di jQuery proxy restituirà una funzione legata a un contesto specifico:

PageObject.prototype.loadPage = function(url) { 
    return $.when($.mobile.loadPage("pages/" + url)) 
    .done($.proxy(this.successFunction, this)); 
}; 

C'è anche del bind che funziona in modo simile, ma deve essere spessorato nei browser meno recenti ES5

PageObject.prototype.loadPage = function(url) { 
    return $.when($.mobile.loadPage("pages/" + url)) 
    .done(this.successFunction.bind(this)); 
}; 

apply e call possono eseguire immediatamente una funzione y con il contesto specificato, ma proxy e bind restituiscono una funzione che può essere utilizzata in un secondo momento o passata ad altre funzioni.

+0

Risposta fantastica, questo è esattamente ciò di cui avevo bisogno (e stavo impazzendo cercando di capirlo). Ho finito per usare la versione $ .proxy che hai postato. Grazie! – Chris

2

La "variabile" this in JavaScript viene chiamata "oggetto chiamante" ed è determinata quando viene chiamata la sua funzione di inclusione (non quando è definita). Può essere impostato alcuni modi diversi:

  1. è possibile impostare utilizzando il . operatore (ad es myObject.myFunction())
  2. È possibile impostare utilizzando call() o apply() i metodi di una funzione
  3. Si può (sotto ES5) si legano in modo permanente utilizzando bind() il metodo della funzione
  4. si imposterà l'oggetto globale se nessuno dei metodi di cui sopra impostarlo su qualcos'altro

La cosa importante da capire è che (a parte il metodo 3 sopra), è tutto su come viene chiamata la funzione quando viene chiamata, non su come viene fatto riferimento, non su come viene memorizzato, non su dove è stato creato.

Nel tuo caso, stai passando this.successFunction come riferimento a una funzione per essere chiamato da jQuery, ma non lo chiama in quel modo (perché ha appena ottenuto un riferimento alla funzione, non tutte le informazioni su come tale funzione dovrebbe essere chiamato).

Ci sono alcuni trucchi di fantasia è possibile utilizzare con .bind() metodi di $.proxy() jQuery o ES5 di, ma quando si scende ad esso, il modo più semplice per gestire la cosa è quello di mantenere semplicemente this attraverso una variabile di chiusura con ambito e utilizzare un funzione wrapper:

PageObject.prototype.loadPage = function(url) { 
    var self = this; 
    return $.when($.mobile.loadPage("pages/" + url)) 
      .done(function() { self.successFunction(); }); 
}; 

si noti che stiamo usando il metodo 1 di legare in modo esplicito successFunction 's chiamata oggetto essere lo stesso oggetto chiamando di loadPage.È breve, semplice, chiaro, funziona bene con ES3 e non dipende da jQuery.

+0

+1 per ciò che accade dietro le quinte, ma io preferisco i trucchi di fantasia, se disponibili, in quanto mantiene il codice più pulito. – Dennis