W3docs

Métodos de Prototype em JavaScript Sem __proto__

Aprenda os métodos modernos de prototype do JavaScript — Object.create(), getPrototypeOf(), setPrototypeOf() — e como usar objects sem prototype como dicionários seguros.

Todo object JavaScript está vinculado a outro object chamado seu prototype, e as buscas de propriedades percorrem essa cadeia. A forma antiga de ler ou alterar esse vínculo era a propriedade especial __proto__, mas ela apresenta problemas reais: é um acessor herdado (não um slot de dado normal), comporta-se de forma inconsistente como chave de object e pode ser explorada para corromper objects. O JavaScript moderno a substitui por métodos explícitos e previsíveis no construtor Object.

Este capítulo apresenta os métodos padrão de prototype — Object.create(), Object.getPrototypeOf() e Object.setPrototypeOf() — e os helpers de inspeção Object.keys(), Object.values(), Object.entries() e Object.hasOwn(). Em seguida, aborda o caso de uso mais útil de um object sem prototype: um "dicionário" seguro para chaves arbitrárias.

Para entender melhor como a cadeia funciona, consulte Herança Prototípica e Além.

Lendo e Definindo um Prototype

Use Object.getPrototypeOf() para ler o prototype de um object e Object.setPrototypeOf() para alterá-lo. Esses são os substitutos padronizados para leitura e escrita de __proto__.

javascript— editable

Object.create(proto) cria um object completamente novo cujo prototype é exatamente proto. É a forma mais limpa de criar um object com um prototype escolhido sem usar __proto__ de forma alguma.

Por Que Evitar __proto__

__proto__ é um getter/setter definido em Object.prototype, não uma propriedade que existe no seu object. Essa diferença causa dois problemas práticos:

  • Pode falhar ou se comportar de forma estranha como chave de dado. Como obj.__proto__ = value aciona o setter, você não pode armazenar de forma confiável uma chave literalmente chamada "__proto__" em um object comum — atribuir um não-object é silenciosamente ignorado, e atribuir um object muda o prototype em vez de adicionar uma chave.
  • É uma superfície de ataque conhecida ("prototype pollution"). Código que copia chaves não confiáveis para um object pode ser induzido a escrever em __proto__, poluindo Object.prototype para todo o programa.

Os métodos padronizados são explícitos quanto à intenção: getPrototypeOf/setPrototypeOf alteram o prototype, enquanto escritas de propriedades normais nunca o tocam.

javascript— editable

Objects Sem Prototype

Object.create(null) cria um object cujo prototype é null. Ele não herda nada — nem mesmo toString, hasOwnProperty, ou o acessor __proto__.

javascript— editable

O Problema do Dicionário que Ele Resolve

Um padrão comum é usar um object simples como mapa de chaves string para valores. O problema é que um {} simples já herda chaves de Object.prototype, portanto chaves fornecidas pelo usuário como "constructor", "toString" ou "__proto__" colidem com os nomes herdados e quebram as buscas.

javascript— editable

Um object com prototype null não possui chaves herdadas, portanto cada chave se comporta exatamente como escrita — incluindo "__proto__":

javascript— editable

É por isso que objects com prototype null formam dicionários seguros para chaves não confiáveis. (O Map embutido é outra boa escolha e permite chaves não-string.)

Adicionando Métodos a um Object com Prototype Null

Como não há prototype para herdar, você atribui métodos diretamente como propriedades próprias.

javascript— editable

Iterando Chaves, Valores e Entradas

Object.keys(), Object.values() e Object.entries() retornam arrays das propriedades enumeráveis próprias de um object. Crucialmente, eles ignoram a cadeia de prototypes, portanto funcionam de forma idêntica em objects normais e com prototype null. Consulte Object.keys, values, entries para mais detalhes.

javascript— editable

Uma ressalva para objects com prototype null: eles não possuem toString herdado, portanto passá-los diretamente para template literals ou String() lança um erro. Itere com os helpers Object.* (acima) em vez de depender da conversão automática para string.

Verificando Propriedades Próprias com Object.hasOwn()

Para verificar se uma chave é propriedade própria do object (não herdada), prefira Object.hasOwn(). É o substituto moderno de obj.hasOwnProperty() e funciona mesmo em objects com prototype null, que não possuem o método hasOwnProperty de forma alguma.

javascript— editable

Composição com Object.assign()

Quando você quer que um object adquira o comportamento de vários outros, a composição geralmente é mais clara do que uma cadeia de herança única: um object só pode ter um prototype, mas Object.assign(target, ...sources) pode incorporar métodos de muitas fontes copiando suas propriedades enumeráveis próprias para o destino.

javascript— editable

Object.assign() também copia para um object com prototype null, fornecendo um dicionário composto sem superfície herdada:

javascript— editable

Ressalva da cópia superficial: Object.assign() copia valores de propriedade, não clones profundos. Valores de object e array são copiados por referência, portanto a fonte e o destino compartilham os mesmos objects aninhados.

javascript— editable

Para uma cópia profunda e independente, use structuredClone(source) em vez disso.

Boas Práticas

  • Use os métodos padronizados, não __proto__. Recorra a Object.create(), Object.getPrototypeOf() e Object.setPrototypeOf(). Trate __proto__ como um acessor legado a ser evitado no seu próprio código.
  • Evite alterar prototypes após a criação. Definir um prototype escolhido no momento da criação com Object.create(proto) é mais limpo e fácil de raciocinar do que mutá-lo depois com Object.setPrototypeOf().
  • Use Object.create(null) (ou Map) para dicionários de chaves não confiáveis. Isso remove chaves herdadas e previne surpresas de prototype pollution.
  • Prefira Object.hasOwn() a obj.hasOwnProperty(). É mais curto, mais seguro de chamar e funciona em objects com prototype null.
  • Componha com Object.assign() quando precisar de comportamento de múltiplas fontes — lembre-se apenas de que é uma cópia superficial.

Para material relacionado, consulte Métodos de object e "this" e Flags e descritores de propriedade.

Conclusão

Os métodos modernos Object.* de prototype oferecem controle explícito e previsível sobre a cadeia de prototypes, substituindo o acessor quirky __proto__. Object.create(null) produz um object limpo e livre de prototype que é ideal para dicionários, enquanto Object.keys/values/entries, Object.hasOwn() e Object.assign() permitem inspecionar e compor objects com segurança, independentemente do seu prototype.

Prática

Prática
Qual chamada cria um object sem prototype, tornando-o um dicionário seguro para chaves arbitrárias?
Qual chamada cria um object sem prototype, tornando-o um dicionário seguro para chaves arbitrárias?
Was this page helpful?