JavaScript Avançado

Prototype Chain Avançado: Object.create, getPrototypeOf e Herança Real: Do Básico ao Avançado

7 min de leitura

Prototype Chain Avançado: Object.create, getPrototypeOf e Herança Real: Do Básico ao Avançado

Object.create: A Base da Herança Real é o método fundamental para criar herança real em JavaScript. Diferente de construtores tradicionais, ele permite criar um objeto com um protótipo específico, oferecendo controle total sobre a cadeia de protótipos. Esse método foi introduzido no ES5 e revolucionou como implementamos herança, sendo a base das práticas modernas. Note como herda sem tê-lo definido. A busca passa pela cadeia até encontrar em . também aceita um segundo argumento com descritores de propriedade, permitindo configuração granular: Object.getPrototypeOf: Inspecionando a Cadeia retorna o protótipo de um objeto, permitindo navegar e inspecionar a cadeia de protótipos. É essencial para debugging e para construir sistemas que dependem de metaprogramação. Ao contrário de , é a forma padronizada e recomendada. Nível ${profundidade}: Combine com para modificar a cadeia dinamicamente, embora com cuidado devido ao impacto em performance: Herança Real com Múltiplos Níveis A verdadeira potência emerge ao criar hierarquias complexas que refletem relacionamentos reais do domínio. Diferente de herança

<h2>Object.create: A Base da Herança Real</h2>

<p><code>Object.create()</code> é o método fundamental para criar herança real em JavaScript. Diferente de construtores tradicionais, ele permite criar um objeto com um protótipo específico, oferecendo controle total sobre a cadeia de protótipos. Esse método foi introduzido no ES5 e revolucionou como implementamos herança, sendo a base das práticas modernas.</p>

<pre><code class="language-javascript">const animal = {

fazer_som: function() {

return &quot;Som genérico&quot;;

},

dormir: function() {

return &quot;Zzzzz...&quot;;

}

};

const cachorro = Object.create(animal);

cachorro.fazer_som = function() {

return &quot;Au au!&quot;;

};

cachorro.buscar = function() {

return &quot;Trazendo a bolinha!&quot;;

};

console.log(cachorro.fazer_som()); // &quot;Au au!&quot;

console.log(cachorro.dormir()); // &quot;Zzzzz...&quot; (herdado)

console.log(cachorro.buscar()); // &quot;Trazendo a bolinha!&quot;</code></pre>

<p>Note como <code>cachorro</code> herda <code>dormir()</code> sem tê-lo definido. A busca passa pela cadeia até encontrar em <code>animal</code>. <code>Object.create()</code> também aceita um segundo argumento com descritores de propriedade, permitindo configuração granular:</p>

<pre><code class="language-javascript">const veiculo = {

acelerar: function() { return &quot;Acelerando...&quot;; }

};

const carro = Object.create(veiculo, {

portas: {

value: 4,

writable: true,

enumerable: true

},

marca: {

value: &quot;Toyota&quot;,

writable: false,

enumerable: true

}

});

console.log(carro.portas); // 4

console.log(carro.marca); // &quot;Toyota&quot;

carro.portas = 2; // Permitido

// carro.marca = &quot;Honda&quot;; // Erro em strict mode</code></pre>

<h2>Object.getPrototypeOf: Inspecionando a Cadeia</h2>

<p><code>Object.getPrototypeOf()</code> retorna o protótipo de um objeto, permitindo navegar e inspecionar a cadeia de protótipos. É essencial para debugging e para construir sistemas que dependem de metaprogramação. Ao contrário de <code>__proto__</code>, é a forma padronizada e recomendada.</p>

<pre><code class="language-javascript">const pessoa = {

saudar: function() { return &quot;Olá!&quot;; }

};

const joao = Object.create(pessoa);

joao.nome = &quot;João&quot;;

const prototipo_joao = Object.getPrototypeOf(joao);

console.log(prototipo_joao === pessoa); // true

console.log(prototipo_joao.saudar()); // &quot;Olá!&quot;

// Navegar a cadeia completa

function mapear_cadeia(obj) {

let atual = obj;

let profundidade = 0;

while (atual !== null) {

console.log(Nível ${profundidade}:, Object.keys(atual));

atual = Object.getPrototypeOf(atual);

profundidade++;

}

}

mapear_cadeia(joao);

// Nível 0: [ &#039;nome&#039; ]

// Nível 1: [ &#039;saudar&#039; ]

// Nível 2: []</code></pre>

<p>Combine <code>getPrototypeOf()</code> com <code>Object.setPrototypeOf()</code> para modificar a cadeia dinamicamente, embora com cuidado devido ao impacto em performance:</p>

<pre><code class="language-javascript">const funcionario = {

trabalhar: function() { return &quot;Trabalhando...&quot;; }

};

const gerente = {

liderar: function() { return &quot;Liderando time...&quot;; }

};

let carlos = Object.create(funcionario);

console.log(carlos.trabalhar()); // &quot;Trabalhando...&quot;

// Mudar protótipo dinamicamente

Object.setPrototypeOf(carlos, gerente);

console.log(carlos.liderar()); // &quot;Liderando time...&quot;

// carlos.trabalhar(); // Erro: não está mais na cadeia</code></pre>

<h2>Herança Real com Múltiplos Níveis</h2>

<p>A verdadeira potência emerge ao criar hierarquias complexas que refletem relacionamentos reais do domínio. Diferente de herança de classe (que é sintetizada), aqui a herança é literal: objetos herdam diretamente de outros objetos.</p>

<pre><code class="language-javascript">const ser_vivo = {

respirar: function() { return &quot;Respirando...&quot;; },

reproduzir: function() { return &quot;Reproduzindo...&quot;; }

};

const animal_avancado = Object.create(ser_vivo);

animal_avancado.mover = function() { return &quot;Movendo...&quot;; };

animal_avancado.comer = function() { return &quot;Comendo...&quot;; };

const mamifero = Object.create(animal_avancado);

mamifero.amamentar = function() { return &quot;Amamentando...&quot;; };

const cao = Object.create(mamifero);

cao.latir = function() { return &quot;Au au!&quot;; };

cao.nome = &quot;Rex&quot;;

// Verificar a cadeia

console.log(cao.latir()); // &quot;Au au!&quot;

console.log(cao.amamentar()); // &quot;Amamentando...&quot;

console.log(cao.comer()); // &quot;Comendo...&quot;

console.log(cao.respirar()); // &quot;Respirando...&quot;

// Verificar onde cada método vive

console.log(Object.getPrototypeOf(cao) === mamifero); // true

console.log(Object.getPrototypeOf(mamifero) === animal_avancado); // true

console.log(Object.getPrototypeOf(animal_avancado) === ser_vivo); // true</code></pre>

<h3>Padrão OLOO (Objects Linking to Objects)</h3>

<p>Este padrão, popularizado por Kyle Simpson, evita construtor functions totalmente:</p>

<pre><code class="language-javascript">const controle_animal = {

init: function(nome, energia) {

this.nome = nome;

this.energia = energia;

return this;

},

gastar_energia: function(qtd) {

this.energia -= qtd;

return this.energia &gt; 0 ? ${this.nome} tem ${this.energia}% de energia : &quot;Sem energia!&quot;;

}

};

const controle_passaro = Object.create(controle_animal);

controle_passaro.voar = function(km) {

return this.gastar_energia(km * 2) + &quot; - Voando!&quot;;

};

const passaro = Object.create(controle_passaro).init(&quot;Tweety&quot;, 100);

console.log(passaro.voar(10)); // &quot;Tweety tem 80% de energia - Voando!&quot;

console.log(passaro.gastar_energia(20)); // &quot;Tweety tem 60% de energia&quot;</code></pre>

<h2>Conclusão</h2>

<p>Dominar <code>Object.create()</code> e <code>Object.getPrototypeOf()</code> revela que a verdadeira herança em JavaScript não precisa de classes ou construtores complexos. <strong>Primeiro aprendizado:</strong> herança real é objetos ligados a objetos; a cadeia de protótipos é uma busca linear por propriedades. <strong>Segundo aprendizado:</strong> <code>Object.create()</code> oferece controle fino, desde descritores até criação de hierarquias limpas, enquanto <code>getPrototypeOf()</code> permite inspecionar e modificar essa relação. <strong>Terceiro aprendizado:</strong> padrões como OLOO demonstram que código mais legível e flexível emerge quando abandonamos a mentalidade de classes e abraçamos a composição de objetos.</p>

<h2>Referências</h2>

<ul>

<li><a href="https://developer.mozilla.org/pt-BR/docs/Web/JavaScript/Reference/Global_Objects/Object/create" target="_blank" rel="noopener noreferrer">MDN Web Docs - Object.create()</a></li>

<li><a href="https://developer.mozilla.org/pt-BR/docs/Web/JavaScript/Reference/Global_Objects/Object/getPrototypeOf" target="_blank" rel="noopener noreferrer">MDN Web Docs - Object.getPrototypeOf()</a></li>

<li><a href="https://github.com/getify/You-Dont-Know-JS/tree/2nd-ed/objects-classes" target="_blank" rel="noopener noreferrer">You Don&#039;t Know JS: this &amp; Object Prototypes - Kyle Simpson</a></li>

<li><a href="https://javascript.info/prototype-inheritance" target="_blank" rel="noopener noreferrer">JavaScript.info - Prototypal Inheritance</a></li>

<li><a href="https://www.ecma-international.org/ecma-262/" target="_blank" rel="noopener noreferrer">ECMAScript 2015 Specification - Prototype Objects</a></li>

</ul>

Comentários

Mais em JavaScript Avançado

O que Todo Dev Deve Saber sobre Template Literal Types e Recursive Types em TypeScript
O que Todo Dev Deve Saber sobre Template Literal Types e Recursive Types em TypeScript

Template Literal Types em TypeScript Template Literal Types permitem criar ti...

Como Usar Testes End-to-End com Playwright: Page Object Model e CI Integration em Produção
Como Usar Testes End-to-End com Playwright: Page Object Model e CI Integration em Produção

O que é Playwright e Por Que Page Object Model? Playwright é um framework de...

Dominando Design Patterns em JavaScript: Factory, Singleton e Builder em Projetos Reais
Dominando Design Patterns em JavaScript: Factory, Singleton e Builder em Projetos Reais

O que são Design Patterns? Design Patterns são soluções comprovadas para prob...