this, call, apply e bind
this não é fixo — depende de como a função é chamada, e call/apply/bind existem pra você controlar isso na mão.
Na lição de funções você viu que arrow function não tem this próprio. Mas isso só faz sentido de verdade quando você entende o que determina o this de uma função normal em primeiro lugar — e é isso que costuma gerar o bug mais clássico de JavaScript orientado a objeto.
this depende de como a função é chamada, não de onde foi escrita
const usuario = {
nome: "Ana",
saudar() {
console.log(`Olá, ${this.nome}`);
},
};
usuario.saudar(); // "Olá, Ana" — this é usuario, porque a chamada foi usuario.saudar()
const saudarSolto = usuario.saudar;
saudarSolto(); // "Olá, undefined" — a função é a mesma, mas a ligação com usuario se perdeusaudarSolto é literalmente a mesma função que usuario.saudar. O que muda é como ela é chamada: quando você chama objeto.metodo(), this vira objeto. Quando chama a função "solta", sem nenhum objeto antes do ponto, essa ligação some.
O bug clássico: perder o this num callback
const usuario = {
nome: "Ana",
saudar() {
console.log(`Olá, ${this.nome}`);
},
};
// parece inofensivo, mas quebra:
setTimeout(usuario.saudar, 100); // "Olá, undefined"
// setTimeout chama a função sozinha, sem o "usuario." na frente —
// é exatamente o mesmo problema de saudarSolto() acimaPassar usuario.saudar como argumento entrega só a função, sem o objeto que a acompanhava. Quando setTimeout chama essa função depois, não existe mais nenhum usuario. na frente pra definir o this.
call e apply — chamar a função definindo o this na mão
function saudar(saudacao) {
console.log(`${saudacao}, ${this.nome}`);
}
const ana = { nome: "Ana" };
const bia = { nome: "Bia" };
saudar.call(ana, "Olá"); // "Olá, Ana" — chama agora, this = ana, argumentos um a um
saudar.apply(bia, ["Oi"]); // "Oi, Bia" — igual a call, mas argumentos dentro de um arraycall e apply fazem exatamente a mesma coisa — a única diferença é como você passa os argumentos extras (separados em call, dentro de um array em apply). Os dois chamam a função imediatamente.
bind — não chama agora, devolve uma função nova com this travado
const saudarAna = saudar.bind(ana);
saudarAna("E aí"); // "E aí, Ana" — this já vem travado em ana, não importa como saudarAna for chamada depois
setTimeout(usuario.saudar.bind(usuario), 100); // "Olá, Ana" — corrige o bug do exemplo anteriorO outro jeito de corrigir: arrow function dentro do método
Você já viu esse padrão na lição de funções — vale reforçar por quê ele funciona. Uma arrow function criada dentro de um método herda o this desse método, então não perde a ligação com o objeto:
const usuario2 = {
nome: "Ana",
saudarComAtraso() {
setTimeout(() => {
console.log(`Olá, ${this.nome}`); // this aqui é herdado de saudarComAtraso — que é usuario2
}, 100);
},
};
usuario2.saudarComAtraso(); // "Olá, Ana"Exercício
Dado const carrinho = { itens: ["mouse", "teclado"], contarItens() { return this.itens.length; } }, o código setTimeout(carrinho.contarItens, 100) quebra (this perdido). Corrija usando bind.