<h2>Entendendo o Prototype Chain</h2>
<p>O prototype chain é o mecanismo fundamental de herança em JavaScript. Quando você acessa uma propriedade em um objeto, o JavaScript primeiro procura naquele objeto. Se não encontrar, busca no prototype do objeto, depois no prototype do prototype, e assim sucessivamente até chegar a <code>null</code>. Essa cadeia de prototypes é o que chamamos de prototype chain.</p>
<p>Diferentemente de linguagens baseadas em classes, JavaScript usa herança baseada em protótipos onde objetos herdam diretamente de outros objetos. Entender isso é crucial para escrever código eficiente e evitar armadilhas comuns em produção. Vamos explorar como isso funciona na prática.</p>
<pre><code class="language-javascript">const animal = {
som: function() {
console.log('Som genérico');
}
};
const cachorro = Object.create(animal);
cachorro.latir = function() {
console.log('Au au!');
};
cachorro.som(); // 'Som genérico' - herdado de animal
cachorro.latir(); // 'Au au!' - próprio do objeto</code></pre>
<h2>Construtores e o Operador <code>new</code></h2>
<p>Historicamente, JavaScript usava funções construtoras para criar objetos com prototypes. Quando você chama uma função com <code>new</code>, o JavaScript cria um novo objeto, define seu <code>[[Prototype]]</code> como o <code>prototype</code> da função construtora, e executa a função naquele contexto. Essa abordagem ainda é amplamente usada em código legado e é essencial compreender.</p>
<p>A propriedade <code>prototype</code> de uma função construtora define o que será o <code>[[Prototype]]</code> de todos os objetos criados por ela. Note a diferença: <code>[[Prototype]]</code> é uma propriedade interna (acessível via <code>Object.getPrototypeOf()</code>), enquanto <code>prototype</code> é uma propriedade regular da função.</p>
<pre><code class="language-javascript">function Veiculo(marca, velocidade) {
this.marca = marca;
this.velocidade = velocidade;
}
Veiculo.prototype.acelerar = function() {
this.velocidade += 10;
return ${this.marca} acelerou para ${this.velocidade}km/h;
};
const carro = new Veiculo('Toyota', 60);
console.log(carro.acelerar()); // 'Toyota acelerou para 70km/h'
console.log(Object.getPrototypeOf(carro) === Veiculo.prototype); // true</code></pre>
<h3>Evitando Armadilhas com Prototypes</h3>
<p>Um erro comum é modificar <code>Veiculo.prototype</code> depois de criar instâncias ou compartilhar arrays/objetos entre instâncias. Se você quer propriedades únicas por instância, defina-as no construtor, não no prototype. Propriedades compartilhadas (métodos) vão no prototype.</p>
<pre><code class="language-javascript">function Usuario(nome) {
this.nome = nome;
this.amigos = []; // Correto: cada instância tem seu próprio array
}
Usuario.prototype.adicionarAmigo = function(amigo) {
this.amigos.push(amigo); // Correto: método no prototype
};
const alice = new Usuario('Alice');
const bob = new Usuario('Bob');
alice.adicionarAmigo('Charlie');
console.log(bob.amigos); // [] - Bob não foi afetado</code></pre>
<h2>Herança em Produção com <code>Object.create()</code> e Classes</h2>
<p>Em produção moderna, preferimos <code>Object.create()</code> ou classes ES6. O <code>Object.create()</code> oferece controle explícito sobre o prototype, tornando o código mais legível. Já as classes ES6 são açúcar sintático sobre construtores, mas facilitam a escrita e compreensão da herança.</p>
<pre><code class="language-javascript">// Padrão com Object.create() - explícito e claro
const Animal = {
fazer_som: function() {
console.log('Som');
}
};
const Gato = Object.create(Animal);
Gato.miar = function() {
console.log('Miau!');
};
const meuGato = Object.create(Gato);
meuGato.nome = 'Felix';
meuGato.miar(); // 'Miau!'
meuGato.fazer_som(); // 'Som'</code></pre>
<p>Para hierarquias mais complexas, classes ES6 são superiores. Elas compilam para o mesmo prototype chain, mas com sintaxe muito mais clara. Use <code>extends</code> para herança e <code>super</code> para acessar o prototype pai.</p>
<pre><code class="language-javascript">class Pessoa {
constructor(nome, idade) {
this.nome = nome;
this.idade = idade;
}
apresentar() {
return Olá, meu nome é ${this.nome};
}
}
class Desenvolvedor extends Pessoa {
constructor(nome, idade, linguagem) {
super(nome, idade);
this.linguagem = linguagem;
}
apresentar() {
return ${super.apresentar()} e programo em ${this.linguagem};
}
}
const dev = new Desenvolvedor('Maria', 28, 'JavaScript');
console.log(dev.apresentar());
// 'Olá, meu nome é Maria e programo em JavaScript'</code></pre>
<h3>Boas Práticas em Produção</h3>
<p>Em produção, <strong>sempre use classes ES6</strong> para código novo. Elas são mais seguras, legíveis e os transpiladores as suportam completamente. Evite modificar prototypes de objetos globais como <code>Array.prototype</code> ou <code>Object.prototype</code>. Use <code>Object.freeze()</code> em prototypes críticos para evitar alterações acidentais. Sempre prefira composição quando a hierarquia fica profunda (mais de 3 níveis).</p>
<pre><code class="language-javascript"></code></pre>
<h2>Conclusão</h2>
<p>O prototype chain é o coração de JavaScript e dominar sua herança baseada em protótipos é essencial para código profissional. Os três pontos principais que deve reter: <strong>1) O prototype chain funciona por delegação</strong> — objetos herdam buscando propriedades em seus prototypes sucessivamente; <strong>2) Use classes ES6 em produção</strong> — são mais seguras, legíveis e eliminam armadilhas; <strong>3) Prefira composição para hierarquias complexas</strong> — evita acoplamento excessivo e torna o código mais flexível e testável.</p>
<h2>Referências</h2>
<ul>
<li><a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Inheritance_and_the_prototype_chain" target="_blank" rel="noopener noreferrer">MDN - Inheritance and the prototype chain</a></li>
<li><a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes" target="_blank" rel="noopener noreferrer">MDN - Classes</a></li>
<li><a href="https://www.oreilly.com/library/view/javascript-the-definitive/9781491952016/" target="_blank" rel="noopener noreferrer">JavaScript: The Definitive Guide - David Flanagan</a></li>
<li><a href="https://github.com/getify/You-Dont-Know-JS" target="_blank" rel="noopener noreferrer">You Don't Know JS Yet - Kyle Simpson</a></li>
<li><a href="https://tc39.es/ecma262/#sec-objects" target="_blank" rel="noopener noreferrer">ECMAScript Specification - Objects</a></li>
</ul>