Entendendo o valor de this em JavaScript com exemplos práticos

Regra padrão (default binding)

Cenário 1

console.log('Contexto global', this); // window (no navegador)

No contexto global, this referencia o objeto global (window no navegador).

Cenário 2

function show() {
    console.log('Dentro de função comum', this);
}
show(); // window

Em uma função comum chamada diretamente, this também aponta para o objeto global.

Conclusão 1

Quando a função é chamada sem nenhum contexto explícito, this assume o objeto global (window).

Vínculo implícito (implicit binding)

Cenário 3

function display() {
    console.log(this.val);
}

const objeto = {
    val: 42,
    display
};

objeto.display(); // 42

Ao chamar objeto.display(), o this dentro de display aponta para o objeto objeto.

Cenário 4

const outroObjeto = {
    objeto,
    val: 100
};

outroObjeto.objeto.display(); // 42

Mesmo com dois níveis de aninhamento, this se refere ao objeto mais próximo na cadeia de chamada (no caso, objeto).

Conclusão 2

Quando uma função é invocada como método de um objeto, this aponta para o objeto que contém a referência imediata da função.

Perda de vínculo (losing this)

Cenário 5

function display() {
    console.log(this.val);
}

const objeto = {
    val: 42,
    display
};

const copia = objeto.display;
copia(); // undefined

Ao atribuir a função a uma variável e chamá-la sem cnotexto, this volta para o objeto global (ou undefined em modo estrito), perdendo a referência original.

Cenário 6

const obj1 = {
    texto: 'primeiro',
    fn: function () {
        return this.texto;
    }
};

const obj3 = {
    texto: 'terceiro',
    fn: function () {
        const f = obj1.fn;
        return f();
    }
};

console.log(obj3.fn()); // undefined

Mesmo dentro do método obj3.fn, a função f perde o vínculo com obj1 e this não aponta para nenhum objeto esperado.

Conclusão 3

Se uma função é extraída do objeto e chamada independentemente, o vínculo implícito é perdido. Isso ocorre porque a referência ao objeto é removida no momento da chamada.

Vínculo explícito (explicit binding)

Cenário 7

const copia = objeto.display.bind(objeto);
copia(); // 42

Usando bind, fixamos o this no objeto desejado, resolvendo a perda de contexto.

Cenário 8

const obj3Corrigido = {
    texto: 'terceiro',
    fn: function () {
        const f = obj1.fn;
        return f.call(this);
    }
};

console.log(obj3Corrigido.fn()); // 'terceiro'

Com call (ou apply) psasamos o this desejado dinamicamente. A diferença entre eles é apenas na passagem de argumnetos: call(this, arg1, arg2) e apply(this, [arg1, arg2]).

Uso especial de apply

const lista = ['a', 'b'];
const elementos = [0, 1, 2];
lista.push.apply(lista, elementos);
console.log(lista); // ['a', 'b', 0, 1, 2]

// Em ES6+: lista.push(...elementos)

Cenário 9

class Exemplo {
    nome = 'padrão';

    falar() {
        console.log(this.nome);
    }
}

const inst = new Exemplo();
const metodo = inst.falar;
metodo(); // undefined (perda de contexto em classes)

Métodos de classe também sofrem perda de this ao serem desvinculados – problema comum em React, por exemplo.

Vínculo com new (new binding)

Cenário 10

function Pessoa(nome) {
    this.nome = nome;
}

const p = new Pessoa('Ana');
console.log(p.nome); // Ana

Quando uma função é chamada com new, um novo objeto é criado e this aponta para esse objeto.

Cenário 11

class Animal {
    constructor(tipo) {
        this.tipo = tipo;
    }
}

const a = new Animal('Gato');
console.log(a.tipo); // Gato

O mesmo se aplica a classes, onde o constructor configura o objeto com this.

Conclusão 4

O vínculo explícito (call/apply/bind) tem prioridade sobre o vínculo implícito, e o new binding também sobrepõe o implícito.

Modo estrito (strict mode)

Cenário 12

function estrito() {
    'use strict';
    console.log('Modo estrito:', this);
}

estrito(); // undefined

Em modo estrito, o this padrão é undefined em vez do objeto global.

Arrow functions

Cenário 13

const arrow = () => {
    'use strict';
    console.log('Arrow em strict:', this);
};

arrow(); // window (não muda)

Arrow functions ignoram o modo estrito e mantêm o this do escopo léxico (onde foram definidas).

Cenário 14

const getVal = () => {
    console.log(this, this.valor);
};

const objArrow = {
    valor: 10,
    getVal
};

objArrow.getVal(); // window, undefined

Arrow functions não são vinculadas implicitamente – o this permanece o do escopo externo.

Cenário 15

objArrow.getVal.bind(objArrow)(); // window, undefined
objArrow.getVal.call(objArrow);   // window, undefined

Nem mesmo vínculo explícito altera o this de uma arrow function.

Cenário 16

const Construtor = () => {
    this.prop = 'teste';
};

const inst = new Construtor(); // TypeError: Construtor is not a constructor

Arrow functions não podem ser usadas como construtores (com new).

Cenário 17

class Usuario {
    nome = 'Maria';

    saudacao = () => {
        console.log(this.nome);
    };
}

const u = new Usuario();
u.saudacao(); // Maria

Usando arrow function como método de classe, o this é capturado no momento da definição, evitando perda de contexto.

Conclusão 5

Arrow functions não permitem reatribuição de this (nem implícita, nem explícita). Elas herdam o this do escopo pai no momento da criação.

Prioridade das regras

Ordem de precedência (da maior para a menor):

  1. Arrow functions (não podem ser alteradas)
  2. new binding (cria novo objeto)
  3. Explicit binding (bind, call, apply)
  4. Implicit binding (chamada como método)
  5. Default binding (global ou undefined em strict)

Tags: javascript this bind call apply

Publicado em 7-17 11:13