Modificando o contexto da palavra-chave this em JavaScript

Em JavaScript a palavra-chave this é uma referência ao objeto atual, porem seu contexto pode mudar dependendo da forma como o objeto é tratado

function fn(){
    console.log(this);
};

fn(); // this === Window
new fn(); // this === fn

Em alguns casos como no exemplo abaixo precisamos que this mantenha um determinado contexto:

var widget = {
    el: document.getElementById('wgt'),
    hide: function() {
       this.el.style.display = 'none';
    },
    init: function(){
        this.el.onclick = this.hide;
        // na função hide this passa a referenciar widget.el,
        // causando um erro pois não existe this.el neste contexto
        // precisamos que continue referenciando apenas widget
    }
}
widget.init();

Uma solução seria salvar o valor de this em uma variável, passar uma função anônima para o método onclick e executar a função hide.

var widget = {
    el: document.getElementById('wgt'),
    hide: function() {
       this.el.style.display = 'none';
    },
    init: function(){
        var self = this;
        this.el.onclick = function(){
            self.hide();
        }
    }
}
widget.init();

Não é uma solução muito elegante, e o JavaScript nos permite fazer isso de uma maneira melhor.

Implementando um método bindTo no objeto Function

Usando o método apply das funções é possivel alterar o contexto de this em funções.
Abaixo um exemplo implementando um novo método no objeto Function:

Function.prototype.bindTo = function(obj){
    var fn = this; // referencia para a função atual
    return function(){
        // obj é o objeto para o qual queremos alterar o contexto de this
        // arguments são os argumentos originais que são recebidos na função retornada
        fn.apply(obj, arguments);
    }
}

O código poderia ser modificado para:

var widget = {
    el: document.getElementById('wgt'),
    hide: function() {
       this.el.style.display = 'none';
    },
    init: function(){
        // usando bindTo agora disponível em qualquer função
        this.el.onclick = this.hide.bindTo(this);
    }
}
widget.init();

Referências

blog comments powered by Disqus