7.8.4 - Classes e Objetos
🧬 Herança em JavaScript — O Poder de Reaproveitar Código!
🧬 Herança em JavaScript — O Poder de Reaproveitar Código!
A herança permite que um objeto "pegue emprestado" propriedades e comportamentos de outro. Isso evita repetição de código e ajuda a organizar melhor nossos programas. Em JavaScript, temos um jeito especial de fazer isso: herança prototipada.
💡 "Herança" é quando um objeto ou classe "filha" ganha tudo o que a classe "pai" tem — como poderes sendo passados de geração em geração! 🧙♂️➡️🧙♀️
🧱 Herança Prototipada: Como funciona?
No JavaScript, objetos herdam de outros objetos por meio de protótipos. Essa é a famosa cadeia de protótipos (prototype chain).
Quando tentamos acessar uma propriedade/método, o JS:
Procura no próprio objeto.
Se não encontrar, sobe para o protótipo (
__proto__
).Continua subindo na cadeia até encontrar ou chegar no
null
.
const animal = {
tipo: "Animal",
fazerSom() {
console.log("Som genérico...");
}
};
const cachorro = Object.create(animal);
cachorro.fazerSom(); // Som genérico...
🧠
Object.create()
cria um novo objeto que herda de outro.
🧪 Exemplo com função construtora
📌 Herdando com e sem parâmetros
function Pessoa(nome) {
this.nome = nome;
this.falar = function () {
console.log("Olá! Meu nome é " + this.nome);
};
}
function Professor(nome, materia) {
Pessoa.call(this, nome); // ⚠️ Chama o construtor pai (Pessoa) com o contexto do filho
this.materia = materia;
}
🔁 Definindo o protótipo e a referência do construtor
Professor.prototype = Object.create(Pessoa.prototype);
Professor.prototype.constructor = Professor; // 🛠 Corrige o ponteiro do construtor
📎 Sobrescrevendo um método
Professor.prototype.falar = function () {
console.log("Sou o professor " + this.nome + ", e ensino " + this.materia);
};
const prof = new Professor("Carlos", "Matemática");
prof.falar(); // "Sou o professor Carlos, e ensino Matemática"
⚠️ Importante: Sempre que usar
Object.create()
para herdar, lembre de corrigir a referênciaconstructor
.
🧠 Observação importante: cuidado com o Object.create()
e o constructor
!
Object.create()
e o constructor
!Quando usamos Object.create()
para criar herança entre objetos ou funções construtoras, estamos dizendo que o novo objeto deve herdar o protótipo de outro.
👀 Mas tem um detalhe importante que MUITA gente esquece:
O
constructor
do novo protótipo continua apontando para o construtor original (pai) — não para o filho! ⚠️
Vamos ver isso na prática:
function Pessoa(nome) {
this.nome = nome;
}
function Professor(nome, materia) {
Pessoa.call(this, nome);
this.materia = materia;
}
// Herança
Professor.prototype = Object.create(Pessoa.prototype);
console.log(Professor.prototype.constructor);
// 👉 Resultado: function Pessoa(nome) {...} ❌
➡️ Isso acontece porque Object.create(Pessoa.prototype)
cria um novo objeto cujo __proto__
é Pessoa.prototype
. Então, o constructor
é herdado de lá também.
🛠️ Como corrigir?
Basta redefinir manualmente o constructor
da função filha:
Professor.prototype.constructor = Professor;
Agora tudo fica certo:
console.log(Professor.prototype.constructor);
// 👉 Resultado: function Professor(nome, materia) {...} ✅
📌 Por que isso é importante?
O constructor
é usado por ferramentas, IDEs e o próprio JavaScript para entender qual função criou um objeto. Se essa referência estiver errada, pode causar:
Confusão na hora de debugar 🔍
Problemas em frameworks que usam
constructor
automaticamente 🔧Dificuldade na manutenção e leitura do código 😵💫
✅ Resumo rápido
Usou Object.create()
constructor
aponta para o pai ❌
Redefina manualmente com Filho.prototype.constructor = Filho
✅
🧠 Observação: Entendendo Professor.prototype
, Professor.constructor
e Professor.prototype.constructor
Professor.prototype
, Professor.constructor
e Professor.prototype.constructor
Essas três estruturas aparecem MUITO quando estamos lidando com herança e protótipos em JavaScript. Vamos entender cada uma delas de forma clara, com comparações e exemplos simples:
🧱 Professor.prototype
Professor.prototype
É o protótipo dos objetos que serão criados quando usamos new Professor()
.
Tudo o que colocamos aqui será compartilhado entre as instâncias criadas com essa função.
function Professor(nome) {
this.nome = nome;
}
Professor.prototype.ensinar = function () {
console.log("Ensinando...");
};
const prof = new Professor("Ana");
prof.ensinar(); // Ensinando...
🧾 Professor.constructor
Professor.constructor
Isso se refere ao construtor da função em si, ou seja, Function
!
Lembre-se: em JavaScript, funções também são objetos — e o construtor das funções é Function
.
console.log(Professor.constructor === Function); // true ✅
🧬 Professor.prototype.constructor
Professor.prototype.constructor
Aqui está o ponto chave! Essa propriedade indica qual função construiu aquele protótipo.
Por padrão, ela aponta para a função construtora correta. Mas quando usamos Object.create()
para fazer herança, ela pode acabar apontando para a função errada!
function Pessoa(nome) {
this.nome = nome;
}
function Professor(nome, materia) {
Pessoa.call(this, nome);
this.materia = materia;
}
// Herança
Professor.prototype = Object.create(Pessoa.prototype);
console.log(Professor.prototype.constructor);
// 👉 Resultado: Pessoa ❌
Professor.prototype.constructor = Professor; // Corrigindo ✅
console.log(Professor.prototype.constructor);
// 👉 Resultado: Professor ✅
🧪 Recapitulando com uma tabela:
Professor.prototype
Protótipo dos objetos Professor
Objeto
Professor.constructor
Quem criou a função Professor
Function
Professor.prototype.constructor
Quem criou o protótipo do Professor
Professor
(ou incorretamente Pessoa
)
⚠️ Atenção: Confundir
constructor
comprototype.constructor
é um dos erros mais comuns entre quem está começando com herança em JS! 😅
✅ Dica prática
Sempre que fizer herança com Object.create()
, verifique se prototype.constructor
está apontando corretamente.
Se não estiver, corrija manualmente:
Filho.prototype.constructor = Filho;
🔍 Observação: O que retorna quando usamos apenas Professor.prototype
?
Professor.prototype
?Quando você acessa Professor.prototype
diretamente no seu código, está consultando o objeto protótipo associado à função construtora Professor
.
📦 Em outras palavras:
console.log(Professor.prototype);
🟰 Retorna um objeto que servirá como base para todas as instâncias criadas com
new Professor()
.
🧠 O que tem dentro desse objeto?
Por padrão, ele começa assim:
function Professor() {}
console.log(Professor.prototype);
// 👉 Resultado:
{
constructor: ƒ Professor()
}
Ou seja, ele contém:
A propriedade
constructor
, que aponta de volta para a própria funçãoProfessor
.
💡 Pra que serve esse objeto?
É nesse Professor.prototype
que você pode adicionar métodos ou propriedades compartilhadas entre todas as instâncias da função.
Professor.prototype.darAula = function () {
console.log("Dando aula!");
};
const prof1 = new Professor();
const prof2 = new Professor();
prof1.darAula(); // Dando aula!
prof2.darAula(); // Dando aula!
✅ Ambos os objetos compartilham o mesmo método sem duplicar o código na memória!
📌 Por que isso é importante?
Entender o que Professor.prototype
retorna é essencial para:
Trabalhar com herança corretamente
Criar métodos otimizados
Entender como funciona o encadeamento de protótipos
Evitar confusão com
__proto__
eprototype.constructor
🛑 Atenção
Professor.prototype
não é o protótipo da função Professor. Ele é o protótipo que será usado pelas instâncias criadas comnew Professor()
!
🔁 Já o Professor.__proto__
(com dois underlines) aponta para Function.prototype
, pois Professor
é uma função.
✅ Resumo rápido
Professor.prototype
Objeto usado como protótipo pelas instâncias criadas
new Professor().__proto__
Sempre é igual a Professor.prototype
📘 ECMAScript 2015 (ES6): Herança com classes
A sintaxe moderna com class
facilita muito o uso da herança:
class Pessoa {
constructor(nome) {
this.nome = nome;
}
falar() {
console.log(`Olá, meu nome é ${this.nome}`);
}
}
class Professor extends Pessoa {
constructor(nome, materia) {
super(nome); // 👈 Chama o construtor da superclasse
this.materia = materia;
}
falar() {
console.log(`Sou o prof. ${this.nome} e ensino ${this.materia}`);
}
get especialidade() {
return this.materia.toUpperCase();
}
set especialidade(novaMateria) {
this.materia = novaMateria;
}
}
const prof2 = new Professor("Joana", "Biologia");
prof2.falar(); // "Sou o prof. Joana e ensino Biologia"
console.log(prof2.especialidade); // BIOLOGIA
prof2.especialidade = "Química";
console.log(prof2.especialidade); // QUÍMICA
🔍 Como funciona por debaixo dos panos?
Mesmo com a sintaxe class
, o JavaScript continua usando protótipos! A classe nada mais é que um açúcar sintático para facilitar a vida de quem programa.
console.log(Object.getPrototypeOf(Professor)); // [Function: Pessoa]
console.log(Object.getPrototypeOf(prof2)); // Pessoa { ... }
🧩 Onde posso definir propriedades e métodos?
Dentro da função construtora
this.nome = "..."
Quando cada instância precisa de um valor diferente
No próprio construtor (estático)
MinhaClasse.algumaFuncao = function () {}
Quando o método é da classe, não do objeto
No protótipo
MinhaClasse.prototype.metodo = function () {}
Quando todas as instâncias compartilham o mesmo comportamento
🧭 Quando usar herança em JavaScript?
✔️ Use quando:
Vários objetos compartilham lógica comum.
Você quer reaproveitar métodos entre objetos semelhantes.
Precisa organizar melhor responsabilidades e comportamentos.
🚫 Evite quando:
Os objetos têm pouco em comum.
A herança deixa o código mais confuso do que ajuda.
Composição seria mais clara do que herança.
💬 Dica: Uma boa regra é "preferir composição à herança", mas usar herança quando o comportamento for realmente compartilhado e hierárquico!
✅ Resumo prático
call()
Pai.call(this)
Chama o construtor pai no contexto do filho
Object.create()
Filho.prototype = Object.create(Pai.prototype)
Faz herança prototipada
constructor
Filho.prototype.constructor = Filho
Corrige a referência do construtor
extends
class Filho extends Pai {}
Herança com classes (ES6)
super()
super()
Chama o construtor da superclasse
get/set
get nome() {}
Criam propriedades especiais
prototype
Classe.prototype.metodo = ...
Define métodos herdáveis
📚 Herança é uma ferramenta poderosa, mas deve ser usada com cuidado e propósito. Aprender como o JavaScript lida com isso te transforma num programador ou programadora muito mais preparado(a)! 🚀
Last updated