Un fait "amusant" JS __proto__

Nov 26 2022
Si vous me suivez depuis assez longtemps, vous savez déjà à quel point j'ai toujours été contre __proto__ et pourtant, depuis qu'il est passé au standard ECMAScript il y a longtemps, il y a encore de rares occasions où je trouve au moins son utilisation pour marquer un objet acceptable : mettre les performances de côté, et veuillez noter que je ne suggère pas du tout l'utilisation de __proto__ dans la nature, ce message existe pour d'autres raisons. Objet.
Photo de Mark Williams sur Unsplash

Si vous me suivez depuis assez longtemps, vous savez déjà à quel point __proto__j'ai toujours été contre et pourtant, depuis qu'il est passé au standard ECMAScript il y a longtemps, il y a encore de rares occasions où je trouve au moins son utilisation pour marquer un objet acceptable :

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

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

Dans Firefox, __proto__ obtient de meilleurs résultats que la nouvelle classe

Mis à part les performances, et veuillez noter que je ne suggère pas du __proto__tout l'utilisation de dans la nature, ce message existe pour d'autres raisons.

Objet.prototype.__proto__

Je suis à peu près sûr que tout le monde sait ce que fait l'accesseur __proto__ , alors j'aimerais vous proposer un défi… et oui, tout cela est valide JS :

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);

Si vous n'avez pas exécuté vous-même ces extraits pour connaître la réponse, je peux vous aider ! Dans le premier défi, la sortie sera false, true, trueet falseencore une fois, et la raison en est que les deux {__proto__}et {["__proto__"]}sont définis comme propriété propre , tandis que l'affectation via la syntaxe, sans utiliser de fonctionnalités de syntaxe spéciales, même avec des guillemets autour, passe en fait par l' Object.prototype.__proto__accesseur.

D'un autre côté, dans le deuxième défi (tous true), peu importe si nous accédons __proto__directement ou en tant que ["__proto__"], de sorte qu'il n'y a fondamentalement aucune symétrie dans la façon dont nous pouvons déclencher le __proto__setter, de la façon dont nous pouvons déclencher le __proto__getter une fois c'est soit une propriété propre, soit une porte d'héritage magique.

… et pas seulement __proto__

Je ne me suis pas vérifié moi-même, mais je pense que chaque __xxx__accesseur spécial hérité souffre de la même __proto__malédiction, alors faites attention de mélanger la dernière syntaxe JS cool pour attribuer des propriétés avec votre intention et vos attentes réelles, car les choses pourraient facilement devenir folles si vous essayez de soyez intelligent dans l' attribution de ces propriétés .

Et c'est tout !

La seule chose à retenir de ce message est probablement résumée ainsi :

  • n'utilisez pas de parties du langage héritées mais encore fonctionnelles, si vous souhaitez éviter les surprises aujourd'hui ou demain sur la façon dont elles se comportent avec la nouvelle syntaxe
  • préférez explicite (et malheureusement plus lent) Object.setPrototypeOfchaque fois que la définition manuelle du prototype d'un objet est strictement requise, mais utilisez des classes dans tous les autres cas chaque fois que cela est possible
  • effacez de votre mémoire ce message ou réduisez-le en une courte phrase comme : " Je ne devrais jamais utiliser __proto__dans mon code " et avancez en apprenant de nouvelles choses fantaisistes qui ne gâchent pas votre cerveau ou vos sentiments