web-dev-qa-db-fra.com

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

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 retourne toujours l'objet avec rating = 3.

Mais si je fais ce qui suit:

newtoy.__proto__.__proto__.__proto__

La chaîne finit par retourner null.

Aussi, dans Internet Explorer, comment vérifier la valeur NULL s'il n'y a pas de propriété __proto__?

150
xdevel2000

J'ai récemment essayé de comprendre ce que je pensais et j'ai finalement créé cette "carte" qui, je pense, donne toute la lumière sur la question. 

http://i.stack.imgur.com/KFzI3.pngenter image description here

Je sais que je ne suis pas le premier à inventer cela, mais il était plus intéressant de le découvrir que le trouver :-). Quoi qu’il en soit, après cela, j’ai trouvé par exemple Ceci est un autre diagramme qui, à mon avis, dit fondamentalement la même chose:

Mise en page d'objets Javascript

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

Je colle le code mentionné dans l'image ici aussi 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 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);
193
drodsou

constructor est une propriété [[DontEnum]] prédéfinie de l'objet pointé par la propriété prototype d'un objet fonction et désignera initialement l'objet fonction lui-même.

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

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

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

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

Si __proto__ est disponible, vous pouvez parcourir la chaîne de prototypes de l’objet. ECMAScript3 ne dispose d'aucun moyen pour cela, car JavaScript n'a pas été conçu pour les hiérarchies d'héritage profondes.

64
Christoph

L'héritage prototypal en JavaScript est basé sur la propriété __proto__, en ce sens que chaque objet hérite du contenu de l'objet référencé par sa propriété __proto__.

La propriété prototype est spéciale uniquement pour les objets Function et uniquement lorsque l'opérateur new est utilisé pour appeler un constructeur Function. Dans ce cas, le __proto__ de l'objet créé sera défini sur Function.prototype du constructeur.

Cela signifie que l'ajout à Function.prototype reflètera automatiquement tous les objets dont __proto__ fait référence à Function.prototype.

Remplacer le Function.prototype du constructeur par un autre objet pas mettra à jour la propriété __proto__ pour tout objet existant.

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

Pour répondre à la première question, j'ai créé un diagramme sur mesure de références __proto__ et prototype. Malheureusement, stackoverflow ne me permet pas d'ajouter l'image avec "moins de 10 réputation". Peut-être une autre fois.

[Edit] La figure utilise [[Prototype]] au lieu de __proto__ car c'est ainsi que la spécification ECMAScript fait référence à des objets internes. J'espère que vous pouvez tout comprendre.

Voici quelques astuces 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 propriété constructor n’existe pas dans les objets créés, mais qu’elle est héritée du prototype.

enter image description here

29
xorcus

Object est Eve et Function est 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 d'Utsaina, je souhaite ajouter plus d'informations utiles.

La chose la plus surprenante pour moi a été de découvrir que Object.__proto__ pointe sur Function.prototype, au lieu de Object.prototype, mais je suis bien sûr, il y a une bonne raison à cela :-)

CA ne devrait pas être. Object.__proto__ NE DOIT PAS pointer sur Object.prototype. Au lieu de cela, l'instance de Objecto, o.__proto__ doit pointer sur Object.prototype.

(Pardonnez-moi d'utiliser les termes class et instance en JavaScript, mais vous le savez :-)

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

De plus, même la classe Function elle-même est une instance de Function elle-même, c'est-à-dire Function.__proto__ === Function.prototype, c'est aussi pourquoi Function === Function.constructor

De plus, la classe régulière Cat est une instance de Function, qui est Cat.__proto__ === Function.prototype.

La raison de ce qui précède est que, lorsque nous créons une classe en JavaScript, nous ne faisons que créer une fonction, qui devrait être une instance de Function. Object et Function sont juste spéciaux, mais ce sont toujours des classes, alors que Cat est une classe ordinaire.

En guise de 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 est function 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 la function Empty() {} (Function.prototype) spéciale? Penses-y :-)

11
Peter Lee

Je ne sais vraiment pas pourquoi les gens ne vous ont pas corrigé au sujet du problème réel dans votre compréhension.

Cela rendrait beaucoup plus facile pour vous de repérer le problème

Voyons 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

Génial, alors regardons ce __proto__

Avant cela, rappelez-vous 2 choses concernant __proto__

  1. Lorsque vous créez un objet avec l'opérateur new, sa propriété interne [[Prototype]]/proto__ est définie sur la propriété prototype (1) de son constructor function ou "créateur" si vous le souhaitez. 

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

Appelons ces deux points "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

Meilleur?

6
Royi Namir

Chaque fonction crée son prototype . Et lorsque nous créons un objet à l'aide de son constructeur, la propriété_PROTO_de mon objet commence à pointer vers le prototype de cette fonction.

2
Apoorv Nag

Si tous ces chiffres sont accablants, examinons 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 la chaîne [[Prototype]]. Pour accéder à cet objet, nous utilisons la propriété prototype 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}

N'oubliez pas que la propriété prototype n'est disponible que pour les fonctions.

STH.constructor

L'objet prototype mentionné ci-dessus n'a aucune propriété 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 de la fonction Gadget, nous avons également créé un objet comme {constructor: Gadget} - qui n’a rien à voir avec Gadget.prototype. Comme constructor fait référence à une fonction qui a créé un prototype d'objet, toy.constructor représente la fonction Gadget. Nous écrivons toy.constructor.prototype et nous obtenons à nouveau {constructor: Gadget}.

Il existe donc un cercle vicieux: vous pouvez utiliser toy.constructor.prototype.constructor.prototype.constructor.prototype.constructor.prototype.constructor.prototype.constructor.prototype.constructor.prototype.constructor.prototype et ce sera toujours Gadget.prototype.

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

STH .__ proto__

Bien que prototype soit une propriété spécifique aux fonctions, __proto__ est disponible pour tous les objets, comme il est décrit dans Object.prototype. Cela fait référence au prototype d'une fonction pouvant créer un objet.

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

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

Ici, toy.__proto__ est Gadget.prototype. Comme Gadget.prototype est un objet ({}) et que les objets sont créés avec la fonction Object (voir l'exemple ci-dessus), nous obtenons Object.prototype. C'est l'objet supérieur en JavaScript et son __proto__ ne peut indiquer que 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
0