Difficulté à marcher manuellement sur la chaîne de prototype

Je voulais essayer de marcher manuellement la chaîne prototype de quelques objets juste pour voir ce que je trouve en cours de route. Cependant, je me suis coincé sur le premier que j'ai essayé. Voici le code:

function MyObject() { } var x = new MyObject(); console.log('--------------------------------------------'); console.log('x.constructor.name: ' + x.constructor.name); console.log('x.constructor.prototype.constructor.name: ' + x.constructor.prototype.constructor.name); console.log(x.constructor.prototype === Function.prototype ? 'Good guess.' : 'No, you are wrong.'); console.log(x.constructor === MyObject ? 'Good guess.' : 'No, you are wrong.'); console.log('--------------------------------------------'); 

Le code ci-dessus résulte de la sortie suivante dans la Console d'outils pour développeurs de Google Chrome:

 -------------------------------------------- x.constructor.name: MyObject x.constructor.prototype.constructor.name: MyObject No, you are wrong. Good guess. -------------------------------------------- 

Il est logique que le constructeur de x soit la fonction MyObject, puisque x a été instancié en utilisant le nouveau mot-clé sur MyObject (cela découle de la définition d'un constructeur). Pour cette raison, je comprends la première ligne de sortie (note: j'ai commencé à compter les lignes de sortie à partir de zéro sur). La deuxième ligne, cependant, me confond. J'aimerais savoir ce qu'est le prototype de MyObject. Apparemment, ce n'est pas un objet de type Fonction, comme l'indique la 3ème ligne de sortie, ce qui me dit que je me trompe. La quatrième ligne de sortie renforce la sortie de la première ligne.

Sur une note plus générale, j'ai supposé que la manière correcte de parcourir la chaîne prototype d'un objet serait de passer de l'objet en question à son constructeur, puis du constructeur au prototype du constructeur, en supposant que cette dernière référence ne soit pas nul. J'ai supposé que ce processus en deux étapes (consistant à aller au constructeur, puis au prototype du constructeur) devrait être répété jusqu'à ce qu'une référence nulle d'un constructeur à un prototype soit atteinte, signifiant ainsi la fin de la chaîne de prototypes. Cela ne semble pas fonctionner, cependant, puisque l'application de cet algorithme au scénario ci-dessus conduit simplement à des références circulaires.

En résumé, j'ai deux questions:

  1. Pourquoi x.constructor === x.constructor.prototype.constructor (ou, en d'autres termes, pourquoi les références circulaires), et quel type d'objet est x.constructor.prototype de toute façon (ou, en d'autres termes, comment Est-ce qu'il a été instancié / d'où est-il venu?)
  2. Comment l'algorithme ci-dessus peut-il être corrigé afin de marcher correctement la chaîne prototype pour l'objet x?

modifier

J'ai rencontré une question similaire sur StackOverflow ici , mais cela ne demande pas explicitement la manière correcte de parcourir la chaîne de prototypes. Il fait remarquer les références circulaires, mais …

Dans la terminologie Javascript, un «prototype» d'un objet se réfère à l'objet dont les propriétés héritent. La manière basée sur les normes pour accéder à ceci est avec Object.getPrototypeOf :

 var protoOfA = Object.getPrototypeOf(a); 

Il existe également l'ancienne façon, non standard mais soutenue par certains navigateurs:

 var protoOfA = a.__proto__; 

Mais si vous avez une fonction F, F.prototype NE renvoie PAS l'objet dont F hérite de rien. Il s'agit plutôt de l'objet à partir duquel les occurrences créées par F héritent:

 function F() {}; a = new F(); console.log(Object.getPrototypeOf(a) === F.prototype); // true 

Lorsque vous définissez une fonction, un objet est créé pour servir de prototype d'instances créées par cette fonction et ce nouvel objet est stocké dans la propriété prototype la fonction.

Les fonctions se comportent comme des objets de plusieurs façons (par exemple, elles peuvent avoir des propriétés), mais elles ne correspondent pas exactement à d'autres objets:

 console.log(typeof a); // "object" console.log(typeof F); // "function" 

Leurs "prototypes" sont mal définis (exemple exécuté en Chrome) (il s'agit apparemment d'un comportement spécifique à Chrome )

 console.log(Object.getPrototypeOf(F)); // "function Empty() {}" console.log(Empty); // ReferenceError: Empty is not defined 

La propriété constructor est étrange. L'interprète ne s'en préoccupe pas . MDN dit avec confusion :

Renvoie une référence à la fonction Objet qui a créé le prototype de l'instance.

En outre, vous pouvez modifier la valeur du constructor sur un objet, mais cela n'a aucun effet sur ce que l'objet est ou comment il se comporte – c'est simplement descriptif.

Donc, pour répondre à vos questions:

Pourquoi x.constructor === x.constructor.prototype.constructor

Pas de bonne raison. C'est un comportement arbitraire auquel les navigateurs ont convergé.

Quel type d'objet est x.constructor.prototype de toute façon

Dans cet exemple, le prototype x de t, identique à Object.getPrototypeOf(x) . Mais en général, vous ne pouvez pas compter sur x.constructor ou tout ce qui en dérive, car c'est arbitraire.

Comment l'algorithme ci-dessus peut-il être corrigé afin de marcher correctement la chaîne prototype pour l'objet x?

 for (var p = x ; p != null ; p = Object.getPrototypeOf(p)) { // do something with p } 

Ouais, cela peut être un peu difficile à saisir au début. Je ne peux pas faire mieux que de vous fournir des liens. Ceux-ci m'aident toujours quand je suis en difficulté.

http://dmitrysoshnikov.com/ecmascript/javascript-the-core/

http://mckoss.com/jscript/object.htm

http://zeekat.nl/articles/constructors-considered-mildly-confusing.html

Q1: Pour le "pourquoi" voir les références ci-dessus. x.constructor.prototype est x.__proto__ qui est le prototype "réel" interne de x, du moins dans votre cas où aucune propriété de prototype et constructor n'a été écrasée. Il est créé le moment où vous définissez la fonction MyObject.

Q2: Malheureusement, vous ne pouvez pas le faire de cette façon. Vous pouvez utiliser la propriété __proto__ où elle est prise en charge, mais voir

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/proto