Um fato JS __proto__ “divertido”
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);
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
, true
e false
novamente, 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.setPrototypeOf
sempre 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