Pergunta

Eu estou tendo alguns problemas com o bom e velho JavaScript (sem quadros) em referência a meu objeto em uma função de retorno de chamada.

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

Agora, quando eu criar um novo objeto (após o DOM foi carregado, com um teste de extensão #)

var x = new foo('test');

O 'isto' dentro da função onclick aponta para o teste de extensão # e não o objeto foo.

Como faço para obter uma referência para o meu objeto foo dentro da função onclick?

Foi útil?

Solução

(extraído alguma explicação que estava escondida em comentários em outra resposta)

As mentiras problema na seguinte linha:

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

Aqui, você passar um objeto função a ser usado como retorno. Quando o disparador do evento, a função é chamada, mas agora ele não tem nenhuma associação com qualquer objeto (this).

O problema pode ser resolvido por envolvimento da função (com a sua referência de objecto) em um fecho como se segue:

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

Uma vez que o auto variável foi atribuído este quando o fechamento foi criado, a função de fechamento vai se lembrar do valor da variável auto quando é chamado em um momento posterior.

Uma forma alternativa de resolver isso é fazer uma função de utilidade (e evitar o uso de variáveis ??para a ligação este ):

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

O código atualizado seria semelhante:

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

Function.prototype.bind faz parte do ECMAScript 5 e fornece a mesma funcionalidade. Então você pode fazer:

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

Para navegadores que não suportam ES5 ainda, MDN fornece o seguinte calço :

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

Outras dicas

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

Para o jQuery usuários que estão buscando uma solução para este problema, você deve usar jQuery.proxy

A explicação é que self.onclick não significa o que você acha que isso significa em JavaScript. É realmente significa a função onclick no protótipo do objeto self (sem de modo algum referência a si self).

JavaScript só tem funções e nenhum delegado como C #, por isso não é possível passar um método eo objeto deve ser aplicado como um callback.

A única maneira de chamar um método em um callback é chamá-lo a si mesmo dentro de uma função de chamada de retorno. Porque funções JavaScript são fechamentos, eles são capazes de acessar as variáveis ??declaradas no âmbito eles foram criados em.

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

Uma boa explicação do problema (eu tinha problemas em entender as soluções descritas até agora) é disponível aqui .

Eu escrevi este plugin ...

Eu acho que vai ser útil

jquery.callback

este é um dos mais confusos pontos de JS: os 'isto' variável significa para o objeto mais locais ... mas funções também são objetos, de modo que 'isto' pontos lá. Há outros pontos sutis, mas eu não me lembro de todos eles.

Eu costumo evitar o uso de 'isto', apenas definir um 'eu' variável local e utilizá-lo.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top