Entendendo as Regras de Vinculação do `this` no JavaScript

Em JavaScript, a palavra-chave this comporta-se de maneira diferente em comparação com linguagens orientadas a objetos tradicionais baseadas em classes. O valor de this não é determinado por onde a função foi declardaa, mas sim por como ela é invocada em tempo de execução. Esse objeto de contexto é frequentemente chamado de "contexto de execução".

Para dominar o comportamento do this, é fundamental compreender as cinco regras prinicpais de vinculação (binding) utilizadas pelo motor do JavaScript.

1. Vinculação Padrão (Escopo Global)

Quando uma função é invocada de forma independente, sem nenhum objeto de contexto à sua esquerda, a vinculação padrão é aplicada. Em navegadores, this aponta para o objeto global window. No Node.js, aponta para global.


function exibirStatus() {
  this.statusGlobal = "ativo";
}

exibirStatus();
console.log(statusGlobal); // "ativo"

Atenção ao Strict Mode: Se o código acima for executado em modo estrito ("use strict";), o this não assumirá o objeto global, mas sim undefined. Tentar atribuir propriedades a undefined resultará em um erro TypeError.

2. Vinculação Implícita

Quando uma função é chamada como um método de um objeto, o contexto de execução é definido como o objeto que está à esquerda do ponto. Nesse cenário, this é vinculado implicitamente a esse objeto.


function iniciarMotor() {
  this.ligado = true;
}

const veiculo = {
  ligado: false,
  iniciar: iniciarMotor
};

veiculo.iniciar();
console.log(veiculo.ligado); // true

Como a função iniciarMotor foi envocada através de veiculo.iniciar(), o this dentro da função refere-se ao objeto veiculo.

3. Vinculação Explícita

JavaScript fornece métodos nativos que permitem forçar a vinculação do this a um objeto específico no momento da chamada. São eles: call(), apply() e bind().


function apresentar(nome, idade) {
  console.log(`Nome: ${this.nome}, Idade: ${idade}`);
}

const usuario = { nome: "Carlos" };

// call() passa os argumentos separados por vírgula
apresentar.call(usuario, 30); 

// apply() passa os argumentos em um array
apresentar.apply(usuario, [25]); 

// bind() retorna uma nova função com o this fixado
const apresentarCarlos = apresentar.bind(usuario);
apresentarCarlos(40); 

4. Vinculação com new (Construtores)

Quando uma função é precedida pela palavra-chave new, o JavaScript executa várias ações, incluindo a criação de um novo objeto vazio e a vinculação do this a esse novo objeto. Funções projetadas para isso são chamadas de funções construtoras.


function ConfigurarTema(cor, fonte) {
  this.cor = cor;
  this.fonte = fonte;
}

const temaEscuro = new ConfigurarTema("#000000", "Arial");
console.log(temaEscuro.cor);   // "#000000"
console.log(temaEscuro.fonte); // "Arial"

O uso de new garante que o this aponte para a instância recém-criada (temaEscuro), e não para o escopo global.

5. Perda de Contexto em Callbacks e a Solução com Arrow Functions

Um problema comum ocorre quando funções são passadas como callbacks (como em setTimeout ou eventos de DOM). O contexto do this é perdido e recai sobre a vinculação padrão (escopo global).


function Tarefa(descricao) {
  this.descricao = descricao;
  this.executar = function() {
    console.log(`Executando: ${this.descricao}`);
  };
  
  this.agendar = function() {
    setTimeout(function() {
      // Erro: this aponta para o objeto global (window), não para a instância de Tarefa
      this.executar(); 
    }, 1000);
  };
}

const minhaTarefa = new Tarefa("Limpar banco de dados");
minhaTarefa.agendar(); // Falha com TypeError

Existem duas formas clássicas de resolver esse problema:

Solução A: Variável de Contexto (Self/That)

Antes de entrar no callback, armazene a referência do this em uma variável local.


function Tarefa(descricao) {
  this.descricao = descricao;
  this.executar = function() {
    console.log(`Executando: ${this.descricao}`);
  };
  
  this.agendar = function() {
    const self = this; // Armazena o contexto atual
    setTimeout(function() {
      self.executar(); // Usa a variável self
    }, 1000);
  };
}

Solução B: Arrow Functions (ES6)

Funções de seta não possuem seu próprio this. Elas herdam o this do escopo léxico onde foram definidas, o que as torna ideais para callbacks.


function Tarefa(descricao) {
  this.descricao = descricao;
  this.executar = function() {
    console.log(`Executando: ${this.descricao}`);
  };
  
  this.agendar = function() {
    setTimeout(() => {
      // O this aqui é o mesmo do método agendar, ou seja, a instância de Tarefa
      this.executar(); 
    }, 1000);
  };
}

const minhaTarefa = new Tarefa("Limpar banco de dados");
minhaTarefa.agendar(); // Funciona perfeitamente

Tags: javascript this context-binding ES6 arrow-functions

Publicado em 7-1 02:37