Pregunta

Tengo algunos problemas con el antiguo JavaScript simple (sin marcos) al hacer referencia a mi objeto en una función de devolución de llamada.

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

Ahora cuando creo un nuevo objeto (después de que se haya cargado el DOM, con una prueba span #)

var x = new foo('test');

El 'this' dentro de la función onclick apunta a la prueba span # y no al objeto foo.

¿Cómo obtengo una referencia a mi objeto foo dentro de la función onclick?

¿Fue útil?

Solución

(extrajo alguna explicación que estaba oculta en los comentarios en otra respuesta)

El problema radica en la siguiente línea:

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

Aquí, pasa un objeto de función para utilizarlo como devolución de llamada. Cuando se activa el evento, se llama a la función pero ahora no tiene asociación con ningún objeto (este).

El problema se puede resolver envolviendo la función (con su referencia de objeto) en un cierre de la siguiente manera:

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

Dado que a la variable self se le asignó this cuando se creó el cierre, la función de cierre recordará el valor de la variable self cuando se llame más adelante.

Una forma alternativa de resolver esto es hacer que una utilidad funcione (y evitar usar variables para enlazar this ):

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

El código actualizado se vería así:

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

Function.prototype.bind es parte de ECMAScript 5 y proporciona la misma funcionalidad. Entonces puedes hacer:

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

Para los navegadores que aún no admiten ES5, MDN proporciona la siguiente cuña :

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

Otros consejos

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

Para los usuarios de jQuery que buscan una solución a este problema, deben usar jQuery.proxy

La explicación es que self.onclick no significa lo que crees que significa en JavaScript. En realidad, significa la función onclick en el prototipo del objeto self (sin hacer referencia de ninguna manera a self ).

JavaScript solo tiene funciones y no tiene delegados como C #, por lo que no es posible pasar un método Y el objeto al que debe aplicarse como devolución de llamada.

La única forma de llamar a un método en una devolución de llamada es llamarlo usted mismo dentro de una función de devolución de llamada. Debido a que las funciones de JavaScript son cierres, pueden acceder a las variables declaradas en el ámbito en el que se crearon.

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

Una buena explicación del problema (tuve problemas para comprender las soluciones descritas hasta ahora) es disponible aquí .

Escribí este complemento ...

creo que será útil

jquery.callback

este es uno de los puntos más confusos de JS: la variable 'this' significa para el objeto más local ... pero las funciones también son objetos, por lo que 'this' apunta allí. Hay otros puntos sutiles, pero no los recuerdo todos.

Por lo general, evito usar 'this', solo defino una variable local 'me' y utilizo eso en su lugar.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top