Pourquoi la mutation de la [[prototype]] d'un objet mauvais pour la performance?
Du MDN docs pour la standard setPrototypeOf
function ainsi que la non-standard __proto__
de la propriété:
La mutation de la [[Prototype]] d'un objet, peu importe comment cela est accompli, il est fortement déconseillé, car il est très lent et inévitablement ralentit l'exécution subséquente moderne implémentations de JavaScript.
À l'aide de Function.prototype
pour ajouter des propriétés est la façon d'ajouter des fonctions de membre de classes javascript. Alors, comme le montre l'exemple suivant:
function Foo(){}
function bar(){}
var foo = new Foo();
//This is bad:
//foo.__proto__.bar = bar;
//But this is okay
Foo.prototype.bar = bar;
//Both cause this to be true:
console.log(foo.__proto__.bar == bar); //true
Pourquoi est foo.__proto__.bar = bar;
mauvais? Si son mal n'est pas Foo.prototype.bar = bar;
tout aussi mauvais?
Alors pourquoi cette mise en garde: il est très lent et inévitablement ralentit l'exécution subséquente moderne implémentations JavaScript. Sûrement Foo.prototype.bar = bar;
n'est pas si mauvais que ça.
Mise à jour peut-être par la mutation qu'ils voulaient dire d'une réaffectation. Voir accepté de répondre.
__proto__
est obsolète non-standard de la propriété. ainsi que sur la manière, il serait agréable de voir les réponses que l'adresse de performances de la question directement: Pourquoi est-il "..très lente et, inévitablement, ralentit l'exécution subséquente moderne implémentations JavaScript"?- merci. C'était mon intention. Mise à jour de question pour être plus explicit en mentionnant la nouvelle façon standard.
- Je ne peux pas trouver la réponse, je veux faire référence, mais autant que je me souvienne de modifier le prototype nécessiterait la js moteur de jeter tous les code natif créé par le JIT-compilateur pour ces objets, comme les propriétés ne correspondent plus, ce qui ralentit tout.
- d'accord. C'est pourquoi je me demande pourquoi
foo.__proto__.bar = bar;
est mauvais. - J'imagine qu'ils ont tous deux le même problème. Il semble que la JS moteur aurait besoin de "vider" toute mise en cache de la propriété des résolutions ou d'autres compilé/intermédiaire IL pour tous enchaînés (dérivée) des objets.
- Je suppose qu'il doit dire la mutation après avoir instances créées est mauvais. Deux de ces méthodes pourraient être tout aussi mauvais et Alex réponse s'appliquent.
- Peut-être. Mais je ne suis pas d'accord avec cette réponse, car il me semble jupe toutes les questions relatives à l'explicite mutation (on peut muter sans
__proto__
, comme indiqué) et implique qu'il n'y a pas de telles optimisations en cours (qui auraient un impact sur les performances wrt. les mutations non-nulle). - J'ai trouvé la question et la réponse correspondante que je recherche: dois-je mettre les valeurs par défaut des attributs sur le prototype pour économiser de l'espace? bien que pas entièrement lié je pense que c'est une des raisons pour lesquelles vous ne devriez pas le faire.
Vous devez vous connecter pour publier un commentaire.
Pas. Les deux font la même chose (comme
foo.__proto__ === Foo.prototype
), et les deux sont très bien. Ils sont juste la création d'unbar
bien sur laObject.getPrototypeOf(foo)
objet.Ce que la déclaration se réfère à l'est de l'affectation à la
__proto__
de la propriété elle-même:L'avertissement au
de l'Objet.prototype
de la page va plus dans le détail:Ils simplement que modifier le prototype de la chaîne d' de l'existence d'un objet tue optimisations. Au lieu de cela, vous êtes censé créer un nouvel objet avec un autre prototype de la chaîne via
Object.create()
.Je ne pouvais pas trouver une référence explicite, mais si l'on considère la façon dont V8 cachés de classes sont mis en œuvre, nous pouvons voir ce qui pourrait aller sur ici. Lors de la modification de la chaîne de prototype d'un objet, son type interne des changements - il ne se contente pas de devenir une sous-classe comme lors de l'ajout d'une propriété, mais est complètement inversés. Cela signifie que tous les biens de recherche d'optimisations sont vidées, et précompilés code devront être jetés. Ou simplement, il revient à la non optimisation de code.
Quelques citations notables:
Brendan Eich (vous savez de lui) a dit
Brian Hackett (Mozilla) a dit:
Jeff Walden a dit:
Erik Corry (Google) a dit:
Éric Faust (Mozilla) a dit
fred = Object.create(Object.prototype)
devrait être tout aussi mauvais. Mais ils specifially dire son bon :Instead, create the object with the desired [[Prototype]] using Object.create.
. Je pense que vous avez raison cependant. Ils ont éventuellement optimiséObject.create
.delete MyObject.__proto__['method'];
sans aucun problème?delete
a ses propres problèmes.Object.setPrototypeOf()
est utilisé tout de suite après la création de l'objet et de la chaîne de prototype n'est pas touché par la suite? La principale raison de la demande, c'est queObject.create()
ne peut pas être utilisé pour l'initialisation d'un objet avec des méthodes faisant usage de lasuper
mot-clé. En d'autres termes, la suite sera bien?:const parent = { method() {} }; const child = { method() { super.method() } }; Object.setPrototypeOf(child, parent);
const child = Object.setPrototypeOf({ method() { super.method() } }, parent)
modèle est très bien. Les moteurs doivent être en mesure d'optimiser cela, et si ils ne le font pas, je voudrais déposer une demande de fonctionnalité. Comme vous le dites, c'est le seul moyen de rendre les méthodes de travail dans les littéraux d'objet, aussi il est nécessaire pour des tableaux ou des fonctions personnalisées prototype de chaînes. Viens de l'utiliser dans ces cas.Object.setPrototypeOf
. Aussi, vous pourriez rencontrer des problèmes de performance dans certains moteurs, de sorte que vous devrait référence attentivement, si vous vous souciez de lui. Ensuite, je veux le regarder dans l'aide declass
syntaxe comme une alternative, les moteurs de soins pour optimiser qui mieux depuis que c'est de plus en plus populaire.__proto__
/setPrototypeOf
ne sont pas les mêmes que l'affectation de l'objet prototype. Par exemple, lorsque vous avez une fonction/objet avec des membres qui lui sont assignées:Tout le monde semble être en se concentrant uniquement sur le prototype, et d'oublier que les fonctions peuvent avoir des membres qui lui sont assignées et instancié après la mutation. Il n'y a actuellement pas d'autre moyen de le faire sans l'aide de
__proto__
/setPrototypeOf
. À peine toute personne d'utiliser un constructeur sans la possibilité d'hériter d'un parent fonction constructeur, etObject.create
ne parvient pas à servir.Et en plus, c'est deux
Object.create
appels, qui, à l'heure actuelle, est impie lent en V8 (à la fois le navigateur et le Nœud), ce qui rend__proto__
un choix plus viableOui .prototype= est tout aussi mauvais, d'où l'expression "peu importe comment il est accompli". prototype est un pseudo-objet pour l'extension de la fonctionnalité au niveau de la classe. Sa nature dynamique ralentit l'exécution du script. Ajout d'une fonction de niveau de l'instance, d'autre part, subit beaucoup moins de frais généraux.
Adding a function on the instance level...incurs far less overhead.
- jusqu'à ce que vous avez de nombreux cas.[prototype]
objet. En tant que tel, l'affectation àFn.prototype
n'est pas "juste comme mauvais" parce que c'est copié sur create. (La question porte sur la mutation le prototype de l'objet.)Ici est un repère à l'aide de nœud
v6.11.1
NormalClass: Une classe normale, avec le prototype non édité
PrototypeEdited: Une classe avec le prototype modifié (le
test()
fonction est ajoutée)PrototypeReference: Une classe avec le prototype de la fonction
test()
qui referer à une variable externeRésultats :
Comme vous pouvez le voir, le prototype édité classe est un moyen plus rapide de la classe normale. Le prototype qui a une variable qui se réfèrent à une externe est le plus lent, mais c'est une façon intéressante de modifier les prototypes avec déjà instantied variable
Source :
.__proto__
ou en appelantObject.setProtottypeOf()
, de sorte que l'indice de référence, bien qu'intéressante, n'est pas pertinente à la question posée.