2012-09-06 11 views
11

Estoy intentando que un objeto javascript ejecute un método diferido y cuando es .done() llame una función en ese mismo objeto. Tengo problemas porque "esto" se convierte en el objeto diferido en lugar del objeto que lo llamó.Cambios diferidos de JQuery "esto"

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"); 

¿Cómo envío "esto" a la función success? Este PageObject va a ser ampliado por otros también, por lo que saber "esto" al ejecutar SuccessFunction será muy útil.

Parece simple, y probablemente tenga una respuesta simple. Estaba investigando .apply() pero no estoy seguro de que haya sido útil. Este post sobre el desbordamiento de la pila fue útil un poco, pero se rompió en el momento en que lo puse en la función .done().

Functions as parameters (with parameters) -- JavaScript

+1

FWIW, el objeto diferido no está cambiando esto, es solo cómo funcionan las funciones. El valor de esto no está determinado por cómo/dónde se define una función, sino cómo se llama. –

Respuesta

14

de jQuery proxy devolverá una función ligada a un contexto específico:

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

Hay también de bind que opera de manera similar, pero tiene que colocar cuñas de navegadores antiguos ES5

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

apply y call pueden ejecutar una función immediatel y con el contexto especificado, pero proxy y bind devuelven una función que puede usarse posteriormente o pasarse a otras funciones.

+0

Fantástica respuesta, esto es exactamente lo que necesitaba (y me estaba volviendo loco tratando de descubrirlo). Terminé usando la versión $ .proxy que publicó. ¡Gracias! – Chris

2

La this "variable" en JavaScript se llama el "objeto que llama" y se determina cuando se llama a su función adjunta (no cuando está definida). Se puede configurar de diferentes maneras:

  1. Se puede establecer mediante el uso de la . operador (por ejemplo myObject.myFunction())
  2. Se puede establecer mediante el uso de call() o apply() métodos de una función
  3. Usted puede (bajo ES5) se unen de forma permanente mediante el uso de bind() método
  4. se pondrá por defecto al objeto global si ninguno de los métodos anteriores establece que a otra cosa
de la función

Lo importante de entender es que (aparte del método 3 anterior), se trata de cómo se llama a la función cuando se la llama, no cómo se hace referencia a ella, cómo se almacena ni dónde se crea.

En su caso, está pasando this.successFunction como referencia de función para ser llamado por jQuery, pero no lo llama así (porque acaba de obtener una referencia a la función, no a información sobre cómo funciona esa función debería ser llamado).

Hay unos cuantos trucos de fantasía que puede utilizar con .bind() métodos ES5 de $.proxy() jQuery o de, pero cuando se llega a esto, la forma más sencilla de manejar que es simplemente retener this través de una variable de cierre de ámbito y utilizar una función de contenedor:

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

Tenga en cuenta que estamos usando el método 1 para unirse de forma explícita successFunction 's llamando objeto a ser el mismo que llamar objeto de LoadPage.Es corto, simple, claro, funciona bien en ES3 y no depende de jQuery.

+0

+1 para lo que sucede detrás de escena, pero tiendo a preferir los trucos de fantasía, si están disponibles, ya que mantienen el código más limpio. – Dennis

Cuestiones relacionadas