En quoi __proto__ diffère-t-il de constructor.prototype?

163
function Gadget(name, color)
{
   this.name = name;
   this.color = color;
}

Gadget.prototype.rating = 3

var newtoy = new Gadget("webcam", "black")

newtoy.constructor.prototype.constructor.prototype.constructor.prototype 

Il renvoie toujours l'objet avec rating = 3.

Mais si je fais ce qui suit:

newtoy.__proto__.__proto__.__proto__

La chaîne finit par revenir null.

Également dans Internet Explorer, comment puis-je vérifier la valeur null s'il n'y a pas de __proto__propriété?

xdevel2000
la source
30
Ce diagramme graphique vous aidera à comprendre la différence entre prototype et proto . Vous pouvez suivre la chaîne proto de l'objet newtoy, et vous comprendrez alors pourquoi le 3e Proto de newtoy est nul.
bits
Il est également clair du diagramme qui newtoy.prototypen'est pas égal à newtoy.constructor.prototypeet newtoy.constructor.prototypen'aura donc pas de propriété appelée rating. De même newtoy.constructor.prototype.constructor.property, la propriété ne sera pas appelée rating.
bits
Typo dans le dernier commentaire: newtoy.constructor.prototypeaura donc la propriété appelée rating. De même newtoy.constructor.prototype.constructor.propertyaura également une propriété appelée notation.
bits
1
@Royi Namir J'ai téléchargé jsViz sur github. Voici le site de démonstration . S'il vous plaît, ne vous inquiétez pas de la façon dont le code réel est non maintenu (et sale). C'est un projet très ancien que je n'ai pas touché depuis toujours.
bits

Réponses:

210

J'ai essayé de comprendre cela récemment et j'ai finalement trouvé cette "carte" qui, je pense, jette toute la lumière sur la question

http://i.stack.imgur.com/KFzI3.png entrez la description de l'image ici

Je sais que je ne suis pas le premier à inventer ça, mais c'était plus intéressant de comprendre que de le trouver :-). Quoi qu'il en soit, après cela, j'ai trouvé par exemple cet autre diagramme qui, je pense, dit fondamentalement la même chose:

Disposition des objets Javascript

La chose la plus surprenante pour moi a été de découvrir que cela Object.__proto__indique Function.prototypeplutôt que Object.prototype, mais je suis sûr qu'il y a une bonne raison à cela :-)

Je colle également le code mentionné dans l'image ici si quelqu'un veut le tester. Notez que certaines propriétés sont ajoutées aux objets pour vous permettre de savoir facilement où nous en sommes après quelques sauts:

Object.O1='';
Object.prototype.Op1='';

Function.F1 = '';
Function.prototype.Fp1 = '';

Cat = function(){};
Cat.C1 = '';
Cat.prototype.Cp1 = '';

mycat = new Cat();
o = {};

// EDITED: using console.dir now instead of console.log
console.dir(mycat);
console.dir(o);
drodsou
la source
2
@utsaina Très cool. Vérifiez une autre représentation graphique du code publié par OP. Et je pense que nos schémas sont en accord en termes de détails techniques.
bits
43
La raison pour laquelle Object.__proto__pointe vers Function.prototypeest parce Object()qu'en elle-même est une fonction native qui instancie un objet vide. Par conséquent, Object()est une fonction. Vous constaterez que toutes les __proto__propriétés des autres principaux types natifs pointent vers Function.prototype. Object, Function, String, NumberEt Arraytous Hériter le prototype de fonction.
Swivel
@drodsou votre 2ème lien est génial. Vérifiez-le maintenant s'il vous plaît;) mollypages.org/misc/js.mp Belle explication: D
abhisekp
@Swivel "Par conséquent, Object () est une fonction" - vouliez-vous dire que Object est une fonction? sans ()
giorgim
2
@GiorgiMoniava Correct. Objectelle-même est une fonction; le résultat de l'exécution de callable Object(c'est-à-dire la valeur de retour de running Object()) n'est pas une fonction.
Pivoter
67

constructorest une propriété [[DontEnum]] prédéfinie de l'objet pointé par la prototypepropriété d'un objet fonction et pointera initialement vers l'objet fonction lui-même.

__proto__ équivaut à la propriété [[Prototype]] interne d'un objet, c'est-à-dire son prototype réel.

Lorsque vous créez un objet avec l' newopérateur, sa propriété interne [[Prototype]] sera définie sur l'objet pointé par la prototypepropriété de la fonction constructeur .

Cela signifie que .constructorsera évalué à .__proto__.constructor, c'est- à -dire la fonction constructeur utilisée pour créer l'objet, et comme nous l'avons appris, la protoypepropriété de cette fonction a été utilisée pour définir le [[Prototype]] de l'objet.

Il s'ensuit que .constructor.prototype.constructorc'est identique à .constructor(tant que ces propriétés n'ont pas été écrasées); voir ici pour une explication plus détaillée.

S'il __proto__est disponible, vous pouvez parcourir la chaîne de prototypes réels de l'objet. Il n'y a aucun moyen de le faire dans ECMAScript3 simple car JavaScript n'a pas été conçu pour les hiérarchies d'héritage profondes.

Christoph
la source
3
Ce lien «ici» est l'étalon-or. Allez-y si vous voulez la description complète.
Ricalsin
Belle prise avec .constructor.prototypechaînage. Je n'étais pas non plus clair pour moi, alors que je n'ai pas vu que c'était .constructorégal .__proto__.constructor. Ce qui signifie simplement passer de la fonction du constructeur à son prototype.
Johnny_D
30

L'héritage prototypique en JavaScript est basé sur la __proto__propriété dans le sens où chaque objet hérite du contenu de l'objet référencé par sa __proto__propriété.

La prototypepropriété est spéciale uniquement pour les Functionobjets et uniquement lors de l'utilisation de l' newopérateur pour appeler un Functionconstructeur as. Dans ce cas, l'objet créé __proto__sera défini sur constructeur Function.prototype.

Cela signifie que l'ajout à Function.prototypese reflétera automatiquement sur tous les objets __proto__référençant le Function.prototype.

Le remplacement du constructeur Function.prototypepar un autre objet ne mettra à jour la __proto__propriété d'aucun des objets déjà existants.

Notez que la __proto__propriété ne doit pas être accédée directement, Object.getPrototypeOf (object) doit être utilisé à la place.

Pour répondre à la première question, j'ai créé un schéma __proto__et des prototyperéférences sur mesure, malheureusement stackoverflow ne me permet pas d'ajouter l'image avec "moins de 10 réputation". Peut-être une autre fois.

[Modifier] La figure utilise [[Prototype]]au lieu de __proto__parce que c'est ainsi que la spécification ECMAScript fait référence aux objets internes. J'espère que vous pourrez tout comprendre.

Voici quelques conseils pour vous aider à comprendre la figure:

red    = JavaScript Function constructor and its prototype
violet = JavaScript Object constructor and its prototype
green  = user-created objects
         (first created using Object constructor or object literal {},
          second using user-defined constructor function)
blue   = user-defined function and its prototype
         (when you create a function, two objects are created in memory:
          the function and its prototype)

Notez que la constructorpropriété n'existe pas dans les objets créés, mais est héritée du prototype.

entrez la description de l'image ici

Xorcus
la source
@xorcus Pouvez-vous s'il vous plaît expliquer ceci: new MyFunction()crée une instance d'objet qui __proto__doit faire référence à son prototype ctor qui est MyFunction.prototype.alors pourquoi fait MyFunction.prototype.__proto__référence Object.prototype? il devrait se référer (comme mon premier échantillon) au prototype de son ctor qui est MyFunction.prototype(remarquez qu'il MyFunction.prototypes'agit d'un instnace de Myfunction)
Royi Namir
@Royi Namir: MyFunction.prototype .__ proto__ fait référence à Object.prototype car MyFunction.prototype est un objet. Object.prototype est hérité par tous les objets (normalement, c'est là que se termine la chaîne d'héritage prototype). Je n'accepte pas que MyFunction.prototype soit une instance de MyFunction. obj instanceof MyFunction <=> MyFunction.prototype.isPrototypeOf (obj) <=> MyFunction.prototype existe dans la chaîne de prototypes obj. Ce n'est pas le cas pour l'objet
MyFunction.prototype
14

Objectest Eve, et Functionest Adam, Adam ( Function) utilise son os ( Function.prototype) pour créer Eve ( Object). Alors, qui a créé Adam ( Function)? - L'inventeur du langage JavaScript :-).

Selon la réponse de utsaina, je souhaite ajouter des informations plus utiles.

La chose la plus surprenante pour moi a été de découvrir que cela Object.__proto__ indique Function.prototypeplutôt que Object.prototype, mais je suis sûr qu'il y a une bonne raison à cela :-)

CA ne devrait pas être. Object.__proto__ne doit PAS pointer vers Object.prototype. Au lieu de cela, l'instance de Object o, o.__proto__doit pointer vers Object.prototype.

(Pardonnez-moi d'utiliser les termes classet instanceen JavaScript, mais vous le savez :-)

Je pense que la classe Objectelle-même est une instance de Function, c'est pourquoi Object.__proto__ === Function.prototype. Par conséquent: Objectest Eve, et Functionest Adam, Adam ( Function) utilise son os ( Function.prototype) pour créer Eve ( Object).

De plus, même la classe Functionelle-même est une instance d' Functionelle-même, c'est-à-direFunction.__proto__ === Function.prototype -dire aussi pourquoiFunction === Function.constructor

De plus, la classe régulière Catest une instance de Function, c'est-à-dire Cat.__proto__ === Function.prototype.

La raison de ce qui précède est que lorsque nous créons une classe en JavaScript, en fait, nous créons simplement une fonction, qui devrait être une instance de Function. Objectet Functionsont juste spéciaux, mais ce sont toujours des classes, alors que Catc'est une classe régulière.

En tant que facteur, dans le moteur JavaScript de Google Chrome, les 4 suivants:

  • Function.prototype
  • Function.__proto__
  • Object.__proto__
  • Cat.__proto__

Ils sont tous ===(absolument égaux) aux 3 autres, et leur valeur estfunction Empty() {}

> Function.prototype
  function Empty() {}
> Function.__proto__
  function Empty() {}
> Object.__proto__
  function Empty() {}
> Cat.__proto__
  function Empty() {}
> Function.prototype === Function.__proto__
  true
> Function.__proto__ === Object.__proto__
  true
> Object.__proto__ === Cat.__proto__
  true

D'ACCORD. Alors, qui crée le spécial function Empty() {}( Function.prototype)? Pensez-y :-)

Peter Lee
la source
D'accord avec cela, sauf pour la dernière chose: à quoi function Empty() {}faites - vous référence pour être égal à Function.prototype, etc.?, Quel est le code que vous avez utilisé dans la console chrome?
drodsou
2
J'ai corrigé la dernière chose que vous avez signalée. Leur valeur est function Empty() {}dans Google Chrome. J'ai également ajouté la sortie de la console.
Peter Lee
toutes les fonctions sont instanceof Function, et par conséquent, toutes les fonctions héritent ( _ _proto_ _) de Function.prototype. C'est aussi simple que ça :)
xorcus
Désolé pour les commentaires sur l'ancien fil. Mais sont-ils créés par Inventor of Language?
Patel Parth
6

Je ne sais vraiment pas pourquoi les gens ne vous ont pas corrigé d'où le problème réel dans votre compréhension.

Cela vous permettrait de repérer beaucoup plus facilement le problème

Voyons donc ce qui se passe:

var newtoy = new Gadget("webcam", "black")

newtoy 
  .constructor //newtoy's constructor function is newtoy ( the function itself)
    .prototype // the function has a prototype property.( all functions has)
      .constructor // constructor here is a **property** (why ? becuase you just did `prototype.constructor`... see the dot ? )  ! it is not(!) the constructor function  !!! this is where your mess begins. it points back to the constructor function itself ( newtoy function)
         .prototype // so again we are at line 3 of this code snippet
            .constructor //same as line 4 ...
                .prototype 
                 rating = 3

Super, alors maintenant regardons ça __proto__

Avant cela, rappelez-vous 2 choses concernant __proto__ :

  1. Lorsque vous créez un objet avec l' newopérateur, sa propriété interne [[Prototype]]/ proto__sera définie sur la prototypepropriété (1) de son constructor functionou "créateur" si vous le souhaitez.

  2. Codé en dur dans JS -: Object.prototype.__proto__est null.

Faisons référence à ces 2 points comme " bill"

newtoy
     .__proto__ // When `newtoy` was created , Js put __proto__'s value equal to the value of the cunstructor's prototype value. which is `Gadget.prototype`.
       .__proto__ // Ok so now our starting point is `Gadget.prototype`. so  regarding "bill" who is the constructor function now? watch out !! it's a simple object ! a regular object ! prototype is a regular object!! so who is the constructor function of that object ? Right , it's the `function Object(){...}`.  Ok .( continuing "bill" ) does it has a `prototype` property ? sure. all function has. it's `Object.prototype`. just remember that when Gadget.prototype was created , it's internal `__proto__` was refered to `Object.prototype` becuase as "bill" says :"..will be set to the `prototype` property of   its `constructor function`"
          .__proto__ // Ok so now our satrting point is `Object.prototype`. STOP. read bullet 2.Object.prototype.__proto__ is null by definition. when Object.prototype ( as an object) was created , they SET THE __PROTO__ AS NULL HARDCODED

Mieux?

Royi Namir
la source
2

Chaque fonction crée son prototype. Et lorsque nous créons un objet en utilisant ce constructeur de fonction, la propriété __proto__ de mon objet commencera à pointer vers le prototype de cette fonction.

Apoorv Nag
la source
1
Je pense que vous vouliez dire la __proto__propriété.
demisx
Oui. Je voulais dire la propriété proto d'un objet. J'espère que les informations ont été utiles.
Apoorv Nag
2

Si tous ces chiffres étaient accablants, voyons ce que signifient les propriétés.

STH.prototype

Lors de la création d'une nouvelle fonction, un objet vide est créé en parallèle et lié à la fonction avec [[Prototype]]chaîne. Pour accéder à cet objet, nous utilisons la prototypepropriété de la fonction.

function Gadget() {}
// in background, new object has been created
// we can access it with Gadget.prototype
// it looks somewhat like {constructor: Gadget}

Gardez à l'esprit que la prototypepropriété n'est disponible que pour les fonctions.

Constructeur STH

L'objet prototype mentionné ci-dessus n'a pas de propriétés sauf une - constructor. Cette propriété représente une fonction qui a créé l'objet prototype.

var toy = new Gadget();

Lors de la création d'une Gadgetfonction, nous avons également créé un objet similaire {constructor: Gadget}- cela n'a rien à voir avec Gadget.prototype. As constructorfait référence à une fonction qui a créé un prototype d'objet, toy.constructorreprésente une Gadgetfonction. Nous écrivons toy.constructor.prototypeet nous obtenons{constructor: Gadget} recommençons.

Par conséquent, il existe un cercle vicieux: vous pouvez utiliser toy.constructor.prototype.constructor.prototype.constructor.prototype.constructor.prototype.constructor.prototype.constructor.prototype.constructor.prototype.constructor.prototypeet ce sera toujours le cas Gadget.prototype.

toy
.constructor    // Gadget
.prototype    // {constructor: Gadget}
.constructor    // Gadget
.prototype    // {constructor: Gadget}
// ...

STH .__ proto__

While prototypeest une propriété spécifique pour les fonctions, __proto__est disponible pour tous les objets au fur et à mesure Object.prototype. Il fait référence au prototype d'une fonction qui peut créer un objet.

[].__proto__ === Array.prototype
// true

({}).__proto === Object.prototype
// true

Voilà, toy.__proto__c'est Gadget.prototype. Comme Gadget.prototypeun objet ({} ) et que les objets sont créés avec la Objectfonction (voir l'exemple ci-dessus), nous obtenons Object.prototype. C'est l'objet le plus élevé en JavaScript et __proto__il ne peut que l'indiquer null.

toy
.__proto__    // Gadget.prototype (object looking like {constructor: Gadget})
.__proto__    // Object.prototype (topmost object in JS)
.__proto__    // null - Object.prototype is the end of any chain
Damian Czapiewski
la source
0

Réponse courte: __proto__ est une référence à la prototypepropriété du constructeur qui a créé l'objet.

Objets en JavaScript

Un objet JavaScript est un type intégré pour une collection de zéro ou plusieurs propriétés. Les propriétés sont des conteneurs qui contiennent d'autres objets, valeurs primitives ou fonctions.

Constructeurs en JavaScript

Les fonctions sont des objets réguliers (qui implémentent [[Call]]en termes ECMA-262) avec la capacité supplémentaire d'être appelables mais jouent un autre rôle en JavaScript: elles deviennent des constructeurs ( usines pour objets) si elles sont appelées via lenew opérateur. Les constructeurs sont donc un analogue approximatif aux classes d'autres langages.

Chaque fonction JavaScript est en fait une instance de l' Functionobjet fonction intégré qui possède une propriété spéciale nommée prototypeutilisée pour implémenter l'héritage basé sur un prototype et les propriétés partagées. Chaque objet créé par une fonction constructeur a une référence implicite (appelée prototype ou __proto__) à la valeur de son constructeur prototype.

Le constructeur prototypeest une sorte de modèle pour la construction d'objets puisque chaque objet créé par le constructeur hérite d'une référence à son prototype.

La chaîne prototype

Un objet spécifie son prototype via la propriété interne [[Prototype]]ou __proto__. La relation prototype entre deux objets concerne l'héritage: chaque objet peut avoir un autre objet comme prototype. Le prototype peut être la nullvaleur.

La chaîne d'objets connectés par la __proto__propriété est appelée la chaîne prototype . Lorsqu'une référence est faite à une propriété dans un objet, cette référence est à la propriété rencontrée dans le premier objet de la chaîne prototype qui contient une propriété de ce nom. La chaîne prototype se comporte comme s'il s'agissait d'un seul objet.

Voir cette image (extraite de ce blog ):

proto.jpg

Chaque fois que vous essayez d'accéder à une propriété dans un objet, JavaScript commence la recherche dans cet objet et continue avec son prototype, le prototype du prototype et ainsi de suite jusqu'à ce que la propriété soit rencontrée ou si elle __proto__contient la valeur null.

Ce type d'héritage utilisant la chaîne prototype est souvent appelé délégation pour éviter toute confusion avec d'autres langages utilisant la chaîne de classes.

Presque tous les objets sont des instances de Object, car il Object.prototypeest le dernier de leur chaîne de prototypes. Mais Object.prototypen'est pas une instance de Objectcar Object.prototype.__proto__détient la valeur null.

Vous pouvez également créer un objet avec un nullprototype comme celui-ci:

var dict = Object.create(null);

Un tel objet est une meilleure carte (dictionnaire) d'un objet littéral, ce qui explique pourquoi ce modèle est parfois appelé le dict motif ( dict du dictionnaire).

Remarque: les objets littéraux créés à l'aide de {}sont des instances de Objectpuisque ({}).__proto__est une référence à Object.prototype.

eigenslacker
la source
Veuillez citer la source des citations et des artefacts que vous utilisez. L'image semble provenir de giamir.com/pseudoclasses-and-prototypal-inheritance-in-JS , avez-vous des droits d'auteur dessus?
Bergi
@Bergi J'ai cité la source de l'image. La plupart des citations que j'ai utilisées sont extraites du standard JS ou du MDN
eigenslacker