voltar aos artigosobject-oriented js
$cd~/artigos/prototypes-object-creation-cadeia-heranca-javascript
Object-Oriented JS
série 33 Conceitos JS·parte 19 de 38

Prototypes & Object Creation: A Cadeia de Herança do JavaScript

18 minVanderlei José Alamino

Como um objeto JavaScript sabe sobre .toString() ou .hasOwnProperty() sem você ter definido? Como objetos herdam de outros sem classes tradicionais? A resposta está na cadeia de protótipos — o mecanismo de herança que torna o JavaScript único.

snippetJavaScript
const mago = { nome: "Gandalf", lancarMagia() { return `${this.nome} lança magia!`; } };const aprendiz = Object.create(mago);aprendiz.nome = "Harry"; console.log(aprendiz.lancarMagia());  // "Harry lança magia!" — herdado de mago

Neste guia da série 33 Conceitos JS — projeto open source criado por Leonardo Maldonado — você vai aprender:

  • Como funciona a busca por propriedades na cadeia de protótipos
  • A diferença entre [[Prototype]], __proto__ e .prototype
  • Object.create(), o operador new e Object.assign()
  • Como inspecionar protótipos e evitar armadilhas comuns

Pré-requisitos: Factories & Classes e this, call, apply & bind.

prototypes-object-creation-cadeia-heranca-javascript.meta.jsonjson

// metadados do artigo

{
  "tag": "object-oriented js",
  "readTime": "18 min",
  "author": "Vanderlei José Alamino",
  "source": "33jsconcepts.com",
  "series": "33 Conceitos JS",
  "part": {
    "current": 19,
    "total": 38
  }
}
abrir fonte original
prototypes-object-creation-cadeia-heranca-javascript.mdmarkdown

Fonte de referência

Conteúdo adaptado a partir do guia original em inglês.

33jsconcepts.com
01

seção

O que é a Cadeia de Protótipos?

Todo objeto tem um link interno [[Prototype]] para outro objeto. Quando você acessa uma propriedade, o JavaScript:

  1. Procura no próprio objeto
  2. Se não encontrar, procura no protótipo
  3. Continua subindo até encontrar ou alcançar null
snippetJavaScript
const mago = {  nome: "Gandalf",  lancarMagia() { return `${this.nome} lança uma magia!`; }}; const aprendiz = Object.create(mago);aprendiz.nome = "Harry"; console.log(aprendiz.nome);           // "Harry" (próprio)console.log(aprendiz.lancarMagia());   // "Harry lança uma magia!" (herdado) // aprendiz → mago → Object.prototype → null
snippettext
aprendiz.lancarMagia()     │     ├─ aprendiz tem lancarMagia? NÃO     ▼   mago.lancarMagia ✓ ENCONTRADO     │     ▼ (se não encontrasse)   Object.prototype (toString, hasOwnProperty…)     │     ▼   null — fim da cadeia

Por isso todos os objetos têm acesso a toString() e hasOwnProperty() — herdados de Object.prototype.

02

seção

[[Prototype]], __proto__ e .prototype

TermoO que éComo acessar
[[Prototype]]Link interno de protótipoNão acessível diretamente
__proto__Getter/setter deprecatedEvite — use APIs modernas
.prototypePropriedade só em funçõesFuncao.prototype
snippetJavaScript
const jogador = { nome: "Alice" };console.log(Object.getPrototypeOf(jogador) === Object.prototype);  // true function Jogador(nome) { this.nome = nome; } const alice = new Jogador("Alice");console.log(Object.getPrototypeOf(alice) === Jogador.prototype);  // trueconsole.log(alice.prototype);  // undefined — instâncias NÃO têm .prototype
snippettext
function Jogador() { … }Jogador.prototype ─────┐                       │ [[Prototype]]const p = new Jogador()│     p ────────────────┘                       │ [[Prototype]]                       ▼                 Object.prototype → null

Não use __proto__ em produção. Prefira Object.getPrototypeOf() para ler e Object.setPrototypeOf() para escrever (com moderação).

03

seção

Busca por Propriedades e Shadowing

snippetJavaScript
const avo = { sobrenomeFamilia: "Silva", dizerOla() { return `Olá, ${this.sobrenomeFamilia}!`; } };const pai = Object.create(avo);pai.profissao = "Engenheiro";const filho = Object.create(pai);filho.nome = "Alice"; console.log(filho.nome);              // "Alice" — filhoconsole.log(filho.profissao);         // "Engenheiro" — paiconsole.log(filho.sobrenomeFamilia);  // "Silva" — avôconsole.log(filho.idade);             // undefined

Shadowing: definir uma propriedade no objeto sombreia a do protótipo sem alterá-la:

snippetJavaScript
const prototipo = { cumprimento: "Olá" };const obj = Object.create(prototipo); console.log(obj.cumprimento);  // "Olá" (protótipo)obj.cumprimento = "Oi";        // cria propriedade própriaconsole.log(obj.cumprimento);        // "Oi"console.log(prototipo.cumprimento);  // "Olá" (inalterado)console.log(obj.hasOwnProperty("cumprimento"));  // true
04

seção

Formas de Criar Objetos

1. Literais de objeto

snippetJavaScript
const jogador = { nome: "Alice", atacar() { return `${this.nome} ataca!`; } };console.log(Object.getPrototypeOf(jogador) === Object.prototype);  // true

2. Object.create()

Cria objeto com protótipo específico — sem chamar construtor:

snippetJavaScript
const prototipoAnimal = {  falar() { return `${this.nome} faz um som.`; },  comer(comida) { return `${this.nome} come ${comida}.`; }}; const cachorro = Object.create(prototipoAnimal);cachorro.nome = "Rex";console.log(cachorro.falar());  // "Rex faz um som."

Sem protótipo — passe null para dicionários seguros:

snippetJavaScript
const dicionario = Object.create(null);console.log("toString" in dicionario);  // false// Sem colisão com hasOwnProperty herdado

3. Operador new — 4 passos

snippettext
1. Criar objeto vazio2. Ligar [[Prototype]] a Construtor.prototype3. Executar construtor com this = novo objeto4. Retornar objeto (salvo retorno explícito de objeto)
snippetJavaScript
function Jogador(nome, vida) {  this.nome = nome;  this.vida = vida;}Jogador.prototype.atacar = function() { return `${this.nome} ataca!`; }; const alice = new Jogador("Alice", 100);console.log(alice.atacar());  // "Alice ataca!"

Simulando new:

snippetJavaScript
function meuNew(Construtor, ...args) {  const obj = Object.create(Construtor.prototype);  const resultado = Construtor.apply(obj, args);  return (resultado !== null && typeof resultado === "object") ? resultado : obj;}

4. Object.assign() — cópia superficial

snippetJavaScript
const padroes = { tema: "claro", fonte: 14 };const prefs = { tema: "escuro" };const config = Object.assign({}, padroes, prefs);console.log(config);  // { tema: "escuro", fonte: 14 }
snippetJavaScript
const original = { nome: "Alice", scores: [90, 85] };const clone = Object.assign({}, original);clone.scores.push(100);console.log(original.scores);  // [90, 85, 100] — array compartilhado! const deep = structuredClone(original);  // clone profundo

Object.assign copia apenas propriedades próprias enumeráveis — não herdadas nem não-enumeráveis.

05

seção

Inspecionando e Modificando Protótipos

snippetJavaScript
// Ler protótipoObject.getPrototypeOf(jogador);Object.getPrototypeOf(Object.prototype);  // null // Mudar protótipo (evite em hot paths — lento)Object.setPrototypeOf(pato, nadador);

instanceof — verifica se Construtor.prototype está na cadeia:

snippetJavaScript
console.log(rex instanceof Cachorro);  // trueconsole.log(rex instanceof Animal);    // trueconsole.log(rex instanceof Object);    // true

isPrototypeOf() — verifica se objeto está na cadeia:

snippetJavaScript
animal.isPrototypeOf(cachorro);  // true
06

seção

Métodos Comuns de Protótipo

snippetJavaScript
const prototipo = { herdado: true };const obj = Object.create(prototipo);obj.proprio = true; obj.hasOwnProperty("proprio");   // trueobj.hasOwnProperty("herdado");   // false"herdado" in obj;                // true — verifica cadeia inteira Object.hasOwn(obj, "proprio");   // ES2022+ — mais seguro que hasOwnProperty
MétodoPrópria?Enumerável?Herdada?
hasOwnProperty(chave)SimAmbasNão
chave in objSimAmbasSim
Object.keys(obj)SimSó enumeráveisNão
Object.getOwnPropertyNames(obj)SimAmbasNão
for...inSimSó enumeráveisSim
snippetJavaScript
Object.keys(obj);                    // ["proprio1", "proprio2"]Object.getOwnPropertyNames(obj);    // inclui não-enumeráveis
07

seção

Armadilhas de Protótipos

Nunca modifique Object.prototype

snippetJavaScript
// ❌ Afeta TODOS os objetosObject.prototype.cumprimentar = () => "Olá";for (const chave in {}) console.log(chave);  // "cumprimentar" aparece!

Confundir .prototype com [[Prototype]]

snippetJavaScript
const alice = new Jogador("Alice");console.log(alice.prototype);  // undefined ❌console.log(Object.getPrototypeOf(alice) === Jogador.prototype);  // true ✅

Poluição de protótipo (segurança)

snippetJavaScript
// ❌ Mesclar JSON não-confiável pode poluir __proto__const payload = JSON.parse('{"__proto__": {"isAdmin": true}}');Object.assign({}, payload);  // perigoso em código legado // ✅ Object.create(null) ou Map para chaves não-confiáveisconst seguro = Object.create(null);const mapa = new Map();

Referência compartilhada no protótipo

snippetJavaScript
// ❌ Array no protótipo — compartilhado por todas as instânciasJogador.prototype.inventario = [];alice.inventario.push("espada");console.log(bob.inventario);  // ["espada"] 😱 // ✅ Inicialize no construtorfunction Jogador(nome) {  this.nome = nome;  this.inventario = [];}
08

seção

Teste Seu Conhecimento

09

seção

Próximos Passos

Você desvendou a cadeia de protótipos — a base real da herança em JavaScript. O último conceito da trilha Object-Oriented JS é Inheritance & Polymorphism — padrões avançados de herança, polimorfismo e quando composição vence hierarquia.

Se quiser revisar a base, volte a Factories & Classes para ver como classes ES6 são açúcar sobre esse sistema.

→ Inheritance & Polymorphism — herança e polimorfismo

Fonte de referência: 33jsconcepts.com/concepts/object-creation-prototypes ⬀

$ summary --quick

Resumo rápido

  • Todo objeto tem [[Prototype]] — cadeia termina em null via Object.prototype
  • Busca sobe a cadeia — propriedade própria tem prioridade (shadowing)
  • .prototype só em funções — instâncias usam Object.getPrototypeOf()
  • Object.create(proto) — protótipo explícito; null para dicionários seguros
  • new faz 4 passos — criar, ligar protótipo, executar construtor, retornar
  • Object.assign é shallow — use structuredClone para cópia profunda
  • hasOwnProperty vs in — própria vs cadeia inteira; prefira Object.hasOwn()
  • Nunca modifique Object.prototype — poluição afeta todo o runtime
  • Métodos no protótipo — memória eficiente; arrays/objetos mutáveis no construtor

Créditos da série

Este artigo faz parte de uma série de estudos inspirada no projeto 33 Conceitos JS, criado por Leonardo Maldonado. Todo o conteúdo original está disponível em 33jsconcepts.com.