Menu

this em JavaScript: Regras de Binding e Erros Comuns

Entenda como o this realmente funciona em JavaScript: as quatro regras de binding, por que arrow functions são diferentes e como escapar do clássico erro 'this is undefined'.

Esta página tem editores executáveis — edite, execute e veja a saída na hora.

this é definido na hora da chamada

Boa parte da confusão com o this em JavaScript vem de uma suposição errada: achar que o this depende de onde a função foi definida. Não é bem assim. O valor de this depende de como a função é chamada.

Veja a mesma função sendo chamada de duas formas diferentes:

Mesma função, this diferente. Na primeira chamada, user está antes do ponto, então this é user. Na segunda chamada, não tem nada antes do ponto, então this é undefined. A função em si não mudou — o que mudou foi o local da chamada.

Guarde essa ideia: para descobrir o valor de this, olhe para a chamada, não para a definição.

As quatro regras de binding do this

Existem quatro formas de o this ser definido. Praticamente toda dúvida sobre this se resolve descobrindo qual dessas regras está em jogo.

1. Chamada como método: obj.fn()

Quando uma função é chamada como propriedade de um objeto, o this é esse objeto:

O que vem antes do ponto vira o this. É só isso.

2. Chamada simples: fn()

Quando você chama a função sem nenhum objeto antes dela, o this é undefined no strict mode (que módulos e classes já ativam automaticamente) ou o objeto global no sloppy mode:

É daqui que nascem aqueles temidos erros de this is undefined. Quando você "arranca" um método do objeto ao qual ele pertence, a chamada deixa de ser uma chamada de método e vira uma chamada de função comum:

Sem o counter. antes da chamada, não rola binding nenhum. A função simplesmente não lembra de qual objeto ela veio.

3. Binding explícito: .call(), .apply() e .bind()

Dá pra forçar o valor de this pra qualquer coisa que você quiser:

.call e .apply executam a função na hora; a diferença está só em como você passa os argumentos. Já o .bind devolve uma nova função com o this fixado de vez — muito útil quando você precisa passar um callback.

4. Chamada com new: new Fn()

Quando você chama uma função com new, o JavaScript cria um objeto novinho e amarra ele ao this:

Por baixo dos panos, as classes usam esse mesmo mecanismo. A gente vai falar delas em um capítulo mais pra frente.

Arrow functions não têm this próprio

As arrow functions quebram as regras acima — e isso é de propósito. Elas simplesmente não fazem o binding do this; em vez disso, herdam o valor do escopo ao redor, congelado no momento em que a arrow é definida:

A arrow function no nível de módulo captura o this do módulo, que é undefined. Mesmo chamando como user.arrow(), a arrow se recusa a trocar o this.

Pode parecer um bug, mas é justamente esse o propósito. As arrow functions brilham quando usadas dentro de métodos, nos casos em que você quer preservar o this externo:

A arrow function dentro do setInterval herda o this do start, que foi chamado como timer.start(). Por isso this.seconds funciona direitinho. Se fosse uma function tradicional ali, ela teria seu próprio this (o que o setInterval passar) e tudo quebraria.

Regra prática: use arrow functions para callbacks dentro de métodos. Para os métodos em si, use funções tradicionais.

A cilada clássica do callback

Essa é a forma mais comum do this sair pelos trilhos no JavaScript. Você passa um método como callback e ele perde o binding:

setTimeout invoca a função como uma chamada comum, e não como c.increment(). Dá pra resolver isso de três formas:

As três formas funcionam. Normalmente, envolver em arrow function é a alternativa mais clara.

this no nível global

No nível mais externo do código, o valor de this depende do ambiente em que ele roda:

  • Script de navegador (não-module): this é window.
  • Módulo ES (inclusive na maior parte do código moderno empacotado por bundlers): this é undefined.
  • Módulo CommonJS do Node.js: this é module.exports.

Se você precisa de uma referência confiável ao objeto global independente do ambiente, use globalThis:

Na prática, evite depender do this no nível superior. Quando você realmente precisar do objeto global, use globalThis. Fora isso, passe os valores explicitamente.

Uma árvore de decisão rápida

Quando bater a dúvida sobre o que this vai ser, percorra esta lista na ordem:

  1. A função é uma arrow function? Então this é o mesmo do escopo onde ela foi criada. Pode ignorar como ela foi chamada.
  2. Foi chamada com new? Então this é o objeto recém-criado.
  3. Foi chamada com .call, .apply ou via função atrelada com bind? Então this é o valor que você passou.
  4. Foi chamada como obj.metodo()? Então this é obj.
  5. Foi chamada como uma função solta fn()? Então this é undefined no strict mode.

Essa escadinha, nessa ordem, resolve qualquer caso.

A seguir: funções de ordem superior

Agora que this deixou de ser um bicho de sete cabeças, você já está pronto para o padrão que torna o JavaScript tão expressivo: tratar funções como valores e passá-las por aí. No próximo tópico vamos falar de funções de ordem superior — aquelas que recebem ou retornam outras funções — e como elas sustentam os métodos de array, os handlers de eventos e praticamente todo código JavaScript do mundo real.

Perguntas frequentes

A que o this se refere em JavaScript?

O this aponta para o objeto sobre o qual a função foi chamada — e não para onde ela foi definida. Em user.greet(), o this é user. Já numa chamada solta como greet(), o this fica undefined no strict mode (ou vira o objeto global no modo sloppy). A regra de ouro é: o que importa é o local da chamada, não o local da definição.

Por que o this está undefined dentro da minha função?

Provavelmente você tirou um método do objeto dele e chamou isoladamente, ou passou como callback. Algo como const fn = user.greet; fn(); perde o binding — não tem objeto antes do ponto no momento da chamada. Dá para resolver com .bind(user), envolvendo numa arrow function, ou chamando direto como user.greet().

Como o this se comporta diferente em arrow functions?

Arrow functions não têm o próprio this. Elas herdam o this do escopo ao redor no momento em que são definidas. Isso torna elas perfeitas para callbacks dentro de métodos, quando você quer preservar o this externo. Também significa que .call(), .apply() e .bind() não conseguem mudar o this de uma arrow function.

O que é o this no topo de um script?

Num script comum rodando no navegador, o this no nível mais externo é o objeto window. Num módulo ES, é undefined. Em módulos CommonJS do Node.js, é o module.exports. Para ter uma referência que funciona em qualquer ambiente, use globalThis, que sempre aponta para o objeto global.

Coddy programming languages illustration

Aprenda a programar com o Coddy

COMEÇAR