Um fato JS __proto__ “divertido”

Nov 26 2022
Se você me segue há bastante tempo, já sabe o quanto eu sempre fui contra __proto__ e, no entanto, desde que chegou ao padrão ECMAScript há muito tempo, ainda há raras ocasiões em que encontro pelo menos seu uso para marcar um objeto aceitável: Deixando o desempenho de lado, e observe que não estou sugerindo o uso de __proto__ de forma alguma, este post existe por outros motivos. Objeto.
Foto de Mark Williams no Unsplash

Se você me segue há bastante tempo, já sabe o quanto __proto__sempre fui contra e, no entanto, desde que chegou ao padrão ECMAScript há muito tempo, ainda há raras ocasiões em que considero aceitável pelo menos seu uso para marcar um objeto :

const factory = (fields, {prototype} = Object) => ({
  __proto__: prototype,
  ...fields
});

// mimic an <a /> reference
factory({href: '/'}, HTMLAnchorElement);

No Firefox, __proto__ pontua melhor que a nova classe

Deixando o desempenho de lado, e observe que não estou sugerindo o uso de __proto__forma alguma, este post existe por outros motivos.

Object.prototype.__proto__

Tenho certeza de que todo mundo sabe o que o __proto__ accessor faz , então gostaria de propor um desafio … e sim, tudo isso é JS válido:

class Test {}
const __proto__ = Test.prototype;

// what do these operations return?
({__proto__} instanceof Test);
({__proto__: __proto__} instanceof Test);
({"__proto__": __proto__} instanceof Test);
({["__proto__"]: __proto__} instanceof Test);

// what do these operations return?
({__proto__}.__proto__ === Test.prototype);
({__proto__: __proto__}.__proto__ === Test.prototype);
({"__proto__": __proto__}.__proto__ === Test.prototype);
({["__proto__"]: __proto__}.__proto__ === Test.prototype);

Se você ainda não executou esses trechos para saber a resposta, posso ajudar com isso! No primeiro desafio, a saída será false, true, truee falsenovamente, e o motivo é que ambos {__proto__}e {["__proto__"]}são definidos como propriedade própria , enquanto a atribuição via sintaxe, sem usar recursos especiais de sintaxe, mesmo com aspas ao redor, passa realmente pelo Object.prototype.__proto__acessador.

Por outro lado, no segundo desafio (all true) realmente não importa se acessamos __proto__diretamente ou como ["__proto__"], de modo que basicamente não há simetria zero na maneira como podemos acionar o __proto__setter, da maneira como podemos acionar o __proto__getter uma vez é uma propriedade própria ou um portão mágico de herança.

… e não apenas __proto__

Eu não verifiquei a mim mesmo, mas acredito que todo __xxx__acessador especial herdado sofre da mesma __proto__maldição, portanto, tenha cuidado ao misturar a sintaxe JS mais recente para atribuir propriedades com sua intenção e expectativas reais, pois as coisas podem facilmente dar errado se você tentar seja inteligente ao atribuir essas propriedades .

E isso é tudo pessoal!

A única conclusão deste post provavelmente é resumida da seguinte forma:

  • não use partes legadas ainda em funcionamento da linguagem, se quiser evitar surpresas hoje, ou amanhã, sobre como elas se comportam com a nova sintaxe
  • prefira explícito (e infelizmente mais lento) Object.setPrototypeOfsempre que definir manualmente o protótipo de um objeto for estritamente necessário, mas use classes em todos os outros casos sempre que possível
  • apague da sua memória esta postagem ou reduza-a a uma frase curta como: “ Eu nunca deveria usar __proto__no meu código ” e prossiga aprendendo coisas novas e sofisticadas que não atrapalhem seu cérebro ou sentimentos