Comment fonctionne le .prototype JavaScript?

2041

Je ne suis pas dans les langages de programmation dynamiques mais j'ai écrit ma juste part de code JavaScript. Je n'ai jamais vraiment compris cette programmation basée sur des prototypes, est-ce que quelqu'un sait comment cela fonctionne?

var obj = new Object();
obj.prototype.test = function() { alert('Hello?'); };
var obj2 = new obj();
obj2.test();

Je me souviens de beaucoup de discussions que j'ai eues avec des gens il y a quelque temps (je ne sais pas exactement ce que je fais) mais d'après ce que je comprends, il n'y a pas de concept de classe. C'est juste un objet, et les instances de ces objets sont des clones de l'original, non?

Mais quel est le but exact de cette propriété ".prototype" en JavaScript? Comment est-ce lié aux instanciations d'objets?

Mise à jour: manière correcte

var obj = new Object(); // not a functional object
obj.prototype.test = function() { alert('Hello?'); }; // this is wrong!

function MyObject() {} // a first class functional object
MyObject.prototype.test = function() { alert('OK'); } // OK

Ces diapositives ont également beaucoup aidé.

John Leidegren
la source
78
John Resig a quelques diapositives sur les prototypes de fonctions qui m'ont été utiles lors de l'examen du sujet (vous pouvez également apporter des modifications au code et voir ce qui se passe ...) http://ejohn.org/apps/learn/#64
John Foster
5
Un excellent matériel de référence, afin de garder cette question informative, placez peut-être certains des commentaires du site de John sur votre réponse au cas où son site serait modifié de manière à ce que votre lien ne soit plus disponible. De toute façon +1, m'a aidé.
Chris
95
+1 pour votre lien vers la diapositive Ninja JavaScript de John Resig # 64 . Partir de là a été vraiment utile et j'ai l'impression de bien comprendre les prototypes.
un nerd payé le
4
Avons-nous vraiment besoin d'un objet fonctionnel pour appliquer le prototype? si oui que pourquoi?
Anshul
6
Cela pourrait vous aider: webdeveasy.com/javascript-prototype
Naor

Réponses:

1007

Chaque objet JavaScript a un "slot" interne appelé [[Prototype]]dont la valeur est soit nullou an object. Vous pouvez considérer un slot comme une propriété sur un objet, interne au moteur JavaScript, caché du code que vous écrivez. Les crochets autour[[Prototype]] sont délibérés et constituent une convention de spécification ECMAScript pour désigner les emplacements internes.

La valeur indiquée par le [[Prototype]] d'un objet, est familièrement connue comme "le prototype de cet objet."

Si vous accédez à une propriété via la notation dot ( obj.propName) ou bracket ( obj['propName']) et que l'objet n'a pas directement une telle propriété (c'est-à-dire une propriété propre , vérifiable via obj.hasOwnProperty('propName')), le runtime recherche une propriété portant ce nom sur l'objet référencé par la [[Prototype]]place. Si le [[Prototype]] aussi ont n'a pas une telle propriété, son [[Prototype]]est vérifiée à son tour, et ainsi de suite. De cette façon, la chaîne prototype de l'objet d'origine est parcourue jusqu'à ce qu'une correspondance soit trouvée ou que sa fin soit atteinte. Au sommet de la chaîne de prototypes se trouve lenull valeur.

Les implémentations JavaScript modernes permettent un accès en lecture et / ou en écriture aux [[Prototype]]manières suivantes:

  1. le new opérateur (configure la chaîne prototype sur l'objet par défaut renvoyé par une fonction constructeur),
  2. Le extendsmot-clé (configure la chaîne prototype lors de l'utilisation de la syntaxe de classe),
  3. Object.createdéfinira l'argument fourni comme celui [[Prototype]]de l'objet résultant,
  4. Object.getPrototypeOfet Object.setPrototypeOf(obtenir / définir l' [[Prototype]] après création d'objet ), et
  5. La propriété d'accesseur normalisé (c.-à-d. Getter / setter) nommée __proto__(similaire à 4.)

Object.getPrototypeOfet Object.setPrototypeOfsont préférés à __proto__, en partie parce que le comportement de o.__proto__ est inhabituel lorsqu'un objet a un prototype denull .

Un objet [[Prototype]] est initialement défini lors de la création de l'objet.

Si vous créez un nouvel objet via new Func(), l'objet [[Prototype]]sera, par défaut, défini sur l'objet référencé parFunc.prototype .

Notez que, par conséquent, toutes les classes et toutes les fonctions pouvant être utilisées avec l' newopérateur ont une propriété nommée .prototypeen plus de leur propre [[Prototype]]emplacement interne. Cette double utilisation du mot "prototype" est la source d'une confusion sans fin parmi les nouveaux venus dans la langue.

En utilisant new de fonctions constructeur nous permet de simuler l'héritage classique en JavaScript; bien que le système d'héritage de JavaScript soit - comme nous l'avons vu - prototypique et non basé sur une classe.

Avant l'introduction de la syntaxe des classes dans JavaScript, les fonctions constructeurs étaient le seul moyen de simuler des classes. Nous pouvons penser aux propriétés de l'objet référencé par la propriété de la fonction constructeur en .prototypetant que membres partagés; c'est à dire. membres identiques pour chaque instance. Dans les systèmes basés sur les classes, les méthodes sont implémentées de la même manière pour chaque instance, de sorte que les méthodes sont conceptuellement ajoutées à la.prototype propriété; Cependant, les champs d'un objet sont spécifiques à l'instance et sont donc ajoutés à l'objet lui-même lors de la construction.

Sans la syntaxe de classe, les développeurs devaient configurer manuellement la chaîne de prototypes pour obtenir des fonctionnalités similaires à l'héritage classique. Cela a conduit à une prépondérance de différentes manières d'y parvenir.

Voici une façon:

function Child() {}
function Parent() {}
Parent.prototype.inheritedMethod = function () { return 'this is inherited' }

function inherit(child, parent) {
  child.prototype = Object.create(parent.prototype)
  child.prototype.constructor = child
  return child;
}

Child = inherit(Child, Parent)
const o = new Child
console.log(o.inheritedMethod()) // 'this is inherited'

... et voici une autre façon:

function Child() {}
function Parent() {}
Parent.prototype.inheritedMethod = function () { return 'this is inherited' }

function inherit(child, parent) {
    function tmp() {}
    tmp.prototype = parent.prototype
    const proto = new tmp()
    proto.constructor = child
    child.prototype = proto
    return child
}

Child = inherit(Child, Parent)
const o = new Child
console.log(o.inheritedMethod()) // 'this is inherited'

La syntaxe de classe introduite dans ES2015 simplifie les choses, en fournissant extends comme "une vraie façon" de configurer la chaîne de prototype afin de simuler l'héritage classique en JavaScript.

Donc, semblable au code ci-dessus, si vous utilisez la syntaxe de classe pour créer un nouvel objet comme ceci:

class Parent { inheritedMethod() { return 'this is inherited' } }
class Child extends Parent {}

const o = new Child
console.log(o.inheritedMethod()) // 'this is inherited'

... l'objet résultant [[Prototype]]sera défini sur une instance de Parent, dont [[Prototype]], à son tour, est Parent.prototype.

Enfin, si vous créez un nouvel objet via Object.create(foo), l'objet résultant [[Prototype]]sera défini sur foo.

Christoph
la source
1
Donc, je fais quelque chose de mal en définissant de nouvelles propriétés sur la propriété prototype dans mon court extrait?
John Leidegren
3
Je pense que c'est ce que signifie avoir des objets fonctionnels en tant que citoyens de première classe.
John Leidegren,
8
Je déteste les choses non standard, en particulier dans les langages de programmation, pourquoi y a-t-il même un proto quand il n'est clairement pas nécessaire?
John Leidegren,
1
@John __proto__ est nécessaire pour un usage interne uniquement par l'interpréteur JS. Chaque objet doit savoir quelles propriétés et méthodes font partie du prototype et lesquelles font partie de l'objet lui-même. L'interpréteur JS doit pouvoir appeler des méthodes prototypées sur un objet.
BMiner
17
noter que l'utilisation de [[Prototype]] est délibérée - ECMA-262 enferme les noms des propriétés internes avec des crochets doubles
Christoph
1798

Dans un langage implémentant l'héritage classique comme Java, C # ou C ++, vous commencez par créer une classe - un plan pour vos objets - puis vous pouvez créer de nouveaux objets à partir de cette classe ou vous pouvez étendre la classe, en définissant une nouvelle classe qui augmente la classe d'origine.

En JavaScript, vous créez d'abord un objet (il n'y a pas de concept de classe), puis vous pouvez augmenter votre propre objet ou en créer de nouveaux. Ce n'est pas difficile, mais un peu étranger et difficile à métaboliser pour quelqu'un habitué à la manière classique.

Exemple:

//Define a functional object to hold persons in JavaScript
var Person = function(name) {
  this.name = name;
};

//Add dynamically to the already defined object a new getter
Person.prototype.getName = function() {
  return this.name;
};

//Create a new object of type Person
var john = new Person("John");

//Try the getter
alert(john.getName());

//If now I modify person, also John gets the updates
Person.prototype.sayMyName = function() {
  alert('Hello, my name is ' + this.getName());
};

//Call the new method on john
john.sayMyName();

Jusqu'à présent, j'étendais l'objet de base, maintenant je crée un autre objet et puis hérite de Person.

//Create a new object of type Customer by defining its constructor. It's not 
//related to Person for now.
var Customer = function(name) {
    this.name = name;
};

//Now I link the objects and to do so, we link the prototype of Customer to 
//a new instance of Person. The prototype is the base that will be used to 
//construct all new instances and also, will modify dynamically all already 
//constructed objects because in JavaScript objects retain a pointer to the 
//prototype
Customer.prototype = new Person();     

//Now I can call the methods of Person on the Customer, let's try, first 
//I need to create a Customer.
var myCustomer = new Customer('Dream Inc.');
myCustomer.sayMyName();

//If I add new methods to Person, they will be added to Customer, but if I
//add new methods to Customer they won't be added to Person. Example:
Customer.prototype.setAmountDue = function(amountDue) {
    this.amountDue = amountDue;
};
Customer.prototype.getAmountDue = function() {
    return this.amountDue;
};

//Let's try:       
myCustomer.setAmountDue(2000);
alert(myCustomer.getAmountDue());

Bien que comme je l'ai dit, je ne peux pas appeler setAmountDue (), getAmountDue () sur une personne.

//The following statement generates an error.
john.setAmountDue(1000);
stivlo
la source
352
Je pense que les réponses sur stackoverflow sont non seulement intéressantes pour l'affiche originale, mais aussi pour une grande communauté d'autres personnes qui se cachent ou qui proviennent de recherches. Et j'en ai fait partie et j'ai pu bénéficier d'anciens postes. Je pense que je pourrais contribuer aux autres réponses en ajoutant quelques exemples de code. À propos de votre question: si vous omettez le nouveau, cela ne fonctionne pas. lorsque j'appelle myCustomer.sayMyName (), elle renvoie "myCustomer.sayMyName n'est pas une fonction". Le moyen le plus simple est d'expérimenter avec Firebug et de voir ce qui se passe.
stivlo
7
Pour autant que je comprends var Person = function (name) {...}; définit une fonction constructeur capable de construire des objets personne. Il n'y a donc pas encore d'objet, seule la fonction constructeur anonyme est affectée à Person. Ceci est une très bonne explication: helephant.com/2008/08/how-javascript-objects-work
stivlo
17
AVERTISSEMENT: cette réponse néglige le fait que le constructeur de classe parent n'est pas appelé par instance. La seule raison pour laquelle cela fonctionne est qu'il a fait exactement la même chose (en définissant le nom) dans le constructeur enfant et parent. Pour une explication plus approfondie des erreurs courantes commises lors de la tentative d'héritage en JavaScript (et une solution finale), veuillez consulter: ce post de débordement de pile
Aaren Cordova
3
Je remarque que cette réponse ne mentionne pas non plus qu'en utilisant "new Person ()" comme prototype, vous définissez en fait la propriété d'instance "name" de "Person" pour être une propriété statique de "Customer" (donc tous les clients les instances auront la même propriété). Bien que ce soit un bon exemple de base, NE FAITES PAS CELA. :) Créez une nouvelle fonction anonyme pour agir comme un "pont" en définissant son prototype sur "Person.prototype", puis créez-en une instance et définissez "Customer.prototype" sur cette instance anonyme à la place.
James Wilkins
10
À propos de la Customer.prototype = new Person();ligne, MDN montre un exemple d'utilisation Customer.prototype = Object.create(Person.prototype)et indique que «Une erreur courante consiste à utiliser« new Person () »» . la source
Rafael Eyng
186

Il s'agit d'un modèle d'objet basé sur un prototype très simple qui serait considéré comme un échantillon lors de l'explication, sans aucun commentaire:

function Person(name){
    this.name = name;
}
Person.prototype.getName = function(){
    console.log(this.name);
}
var person = new Person("George");

Il y a quelques points cruciaux que nous devons considérer avant de passer par le concept du prototype.

1- Comment fonctionnent réellement les fonctions JavaScript:

Pour prendre la première étape, nous devons comprendre comment les fonctions JavaScript fonctionnent réellement, en tant que fonction de classe utilisant un thismot-clé ou simplement en tant que fonction régulière avec ses arguments, ce qu'elle fait et ce qu'elle retourne.

Disons que nous voulons créer un Personmodèle d'objet. mais dans cette étape, je vais essayer de faire exactement la même chose sans utiliser de mot prototype- newclé .

Donc, dans cette étape functions, objectset thismot - clé, sont tout ce que nous avons.

La première question serait de savoir comment un thismot clé pourrait être utile sans utiliser de newmot clé .

Donc pour répondre à cela, disons que nous avons un objet vide, et deux fonctions comme:

var person = {};
function Person(name){  this.name = name;  }

function getName(){
    console.log(this.name);
}

et maintenant sans utiliser de newmot-clé, comment nous pourrions utiliser ces fonctions. JavaScript a donc 3 façons différentes de le faire:

une. la première façon consiste simplement à appeler la fonction en tant que fonction régulière:

Person("George");
getName();//would print the "George" in the console

dans ce cas, ce serait l'objet de contexte actuel, qui est généralement le global window objet dans le navigateur ou GLOBALdans Node.js. Cela signifie que nous aurions, window.name dans le navigateur ou GLOBAL.name dans Node.js, avec "George" comme valeur.

b. nous pouvons attacher à un objet, comme ses propriétés

- La façon la plus simple de le faire est de modifier l' personobjet vide , comme:

person.Person = Person;
person.getName = getName;

de cette façon, nous pouvons les appeler comme:

person.Person("George");
person.getName();// -->"George"

et maintenant l' personobjet est comme:

Object {Person: function, getName: function, name: "George"}

- L'autre façon d'attacher une propriété à un objet est d'utiliser le prototypede cet objet qui peut être trouvé dans n'importe quel objet JavaScript avec le nom de __proto__, et j'ai essayé de l'expliquer un peu dans la partie récapitulative. Ainsi, nous pourrions obtenir le résultat similaire en faisant:

person.__proto__.Person = Person;
person.__proto__.getName = getName;

Mais de cette façon, ce que nous faisons est en train de modifier le Object.prototype, car chaque fois que nous créons un objet JavaScript à l'aide de literals ( { ... }), il est créé en fonction de Object.prototype, ce qui signifie qu'il est attaché à l'objet nouvellement créé en tant qu'attribut nommé __proto__, donc si nous le changeons , comme nous l'avons fait sur notre extrait de code précédent, tous les objets JavaScript seraient modifiés, ce qui n'est pas une bonne pratique. Alors, quelle pourrait être la meilleure pratique maintenant:

person.__proto__ = {
    Person: Person,
    getName: getName
};

et maintenant d'autres objets sont en paix, mais cela ne semble toujours pas être une bonne pratique. Nous avons donc encore une solution, mais pour utiliser cette solution, nous devons revenir à cette ligne de code où l' personobjet a été créé ( var person = {};), puis le changer comme:

var propertiesObject = {
    Person: Person,
    getName: getName
};
var person = Object.create(propertiesObject);

il crée un nouveau JavaScript Objectet attache le propertiesObjectà l' __proto__attribut. Donc, pour vous assurer que vous pouvez faire:

console.log(person.__proto__===propertiesObject); //true

Mais le point délicat ici est que vous avez accès à toutes les propriétés définies au __proto__premier niveau de laperson objet (lisez la partie récapitulative pour plus de détails).


comme vous le voyez en utilisant l'un de ces deux moyens this pointerait exactement vers l' personobjet.

c. JavaScript a une autre façon de fournir la fonction this, qui utilise l' appel ou l' application pour appeler la fonction.

La méthode apply () appelle une fonction avec une valeur donnée et des arguments fournis sous la forme d'un tableau (ou d'un objet de type tableau).

et

La méthode call () appelle une fonction avec une valeur donnée et des arguments fournis individuellement.

de cette façon qui est ma préférée, nous pouvons facilement appeler nos fonctions comme:

Person.call(person, "George");

ou

//apply is more useful when params count is not fixed
Person.apply(person, ["George"]);

getName.call(person);   
getName.apply(person);

ces 3 méthodes sont les étapes initiales importantes pour comprendre la fonctionnalité .prototype.


2- Comment le new mot clé?

c'est la deuxième étape pour comprendre la .prototypefonctionnalité. c'est ce que j'utilise pour simuler le processus:

function Person(name){  this.name = name;  }
my_person_prototype = { getName: function(){ console.log(this.name); } };

dans cette partie, je vais essayer de suivre toutes les étapes que JavaScript prend, sans utiliser le newmot - clé et prototype, lorsque vous utilisez le newmot-clé. donc quand nous le faisons new Person("George"), la Personfonction sert de constructeur, voici ce que fait JavaScript, un par un:

une. tout d'abord, il fait un objet vide, essentiellement un hachage vide comme:

var newObject = {};

b. l'étape suivante que JavaScript prend consiste à attacher tous les objets prototypes à l'objet nouvellement créé

nous avons my_person_prototypeici similaire à l'objet prototype.

for(var key in my_person_prototype){
    newObject[key] = my_person_prototype[key];
}

Ce n'est pas la façon dont JavaScript attache réellement les propriétés définies dans le prototype. La voie actuelle est liée au concept de chaîne prototype.


une. & b. Au lieu de ces deux étapes, vous pouvez obtenir exactement le même résultat en procédant comme suit:

var newObject = Object.create(my_person_prototype);
//here you can check out the __proto__ attribute
console.log(newObject.__proto__ === my_person_prototype); //true
//and also check if you have access to your desired properties
console.log(typeof newObject.getName);//"function"

maintenant nous pouvons appeler la getNamefonction dans notre my_person_prototype:

newObject.getName();

c. puis il donne cet objet au constructeur,

nous pouvons le faire avec notre échantillon comme:

Person.call(newObject, "George");

ou

Person.apply(newObject, ["George"]);

alors le constructeur peut faire ce qu'il veut, parce que l' intérieur de ce constructeur est l'objet qui vient d'être créé.

maintenant le résultat final avant de simuler les autres étapes: Object {name: "George"}


Sommaire:

Fondamentalement, lorsque vous utilisez le nouveau mot-clé sur une fonction, vous appelez cela et cette fonction sert de constructeur, donc quand vous dites:

new FunctionName()

JavaScript crée en interne un objet, un hachage vide, puis il donne cet objet au constructeur, puis le constructeur peut faire ce qu'il veut, car à l' intérieur de ce constructeur est l'objet qui vient d'être créé et ensuite il vous donne cet objet bien sûr si vous n'avez pas utilisé l'instruction return dans votre fonction ou si vous avez mis un return undefined;à la fin de votre corps de fonction.

Ainsi, lorsque JavaScript cherche une propriété sur un objet, la première chose qu'il fait, c'est qu'il la recherche sur cet objet. Et puis il y a une propriété secrète [[prototype]]que nous avons habituellement comme __proto__et cette propriété est ce que JavaScript regarde ensuite. Et quand il regarde à travers __proto__, tant qu'il s'agit encore d'un autre objet JavaScript, il a son propre __proto__attribut, il monte et monte jusqu'à ce qu'il atteigne le point où le suivant __proto__est nul. Le point est le seul objet en JavaScript dont l' __proto__attribut est nul est un Object.prototypeobjet:

console.log(Object.prototype.__proto__===null);//true

et c'est ainsi que l'héritage fonctionne en JavaScript.

La chaîne prototype

En d'autres termes, lorsque vous avez une propriété prototype sur une fonction et que vous en appelez une nouvelle, une fois que JavaScript a fini de regarder cet objet nouvellement créé pour les propriétés, il va regarder les fonctions .prototypeet il est également possible que cet objet ait son propre prototype interne. etc.

Mehran Hatami
la source
6
a) Veuillez ne pas expliquer les prototypes en copiant les propriétés b) La définition du [[prototype]] interne se produit avant l'application de la fonction constructeur sur l'instance, veuillez modifier cet ordre c) jQuery est totalement hors sujet dans cette question
Bergi
1
@Bergi: merci de l'avoir signalé, je vous serais reconnaissant de me faire savoir si ça va maintenant.
Mehran Hatami
7
Pouvez-vous s'il vous plaît faire simple? Vous avez raison sur tous les points, mais les étudiants qui lisent cette explication peuvent être vraiment confus pour la première fois. prenez un exemple plus simple et laissez le code s'expliquer ou ajoutez un tas de commentaires pour clarifier ce que vous voulez dire.
PM
2
@PM: Merci pour vos commentaires. J'ai essayé de le rendre aussi simple que possible, mais je pense que vous avez raison, il a encore quelques points vagues. Je vais donc essayer de le modifier et aussi être plus descriptif. :)
Mehran Hatami
1
@AndreaMattioli parce que de cette façon, vous créez un objet totalement nouveau et remplacez l'ancien qui pourrait également être partagé entre d'autres objets. En remplaçant, __proto__vous supprimez d'abord toutes les propriétés de prototype de niveau supérieur, puis vous avez une nouvelle base de prototypes qui n'est plus partagée, sauf si vous la partagez.
Mehran Hatami
77

Les sept Koans du prototype

Alors que Ciro San descendait le mont Fire Fox après une profonde méditation, son esprit était clair et paisible.

Cependant, sa main était agitée, et en elle-même attrapa un pinceau et nota les notes suivantes.


0) Deux choses différentes peuvent être appelées "prototype":

  • la propriété prototype, comme dans obj.prototype

  • la propriété interne du prototype, notée comme [[Prototype]] dans ES5 .

    Il peut être récupéré via l'ES5 Object.getPrototypeOf().

    Firefox le rend accessible via la __proto__propriété en tant qu'extension. ES6 mentionne désormais certaines exigences facultatives pour __proto__.


1) Ces concepts existent pour répondre à la question:

Quand je le fais obj.property, où JS cherche- .propertyt-il?

Intuitivement, l'héritage classique devrait affecter la recherche de propriété.


2)

  • __proto__est utilisé pour la .recherche de propriété dot comme dans obj.property.
  • .prototypen'est pas utilisé pour la recherche directement, mais indirectement car il détermine __proto__lors de la création de l'objet avec new.

L'ordre de recherche est:

  • objpropriétés ajoutées avec obj.p = ...ouObject.defineProperty(obj, ...)
  • propriétés de obj.__proto__
  • propriétés de obj.__proto__.__proto__, etc.
  • si certains le __proto__sont null, revenez undefined.

Il s'agit de la soi-disant chaîne prototype .

Vous pouvez éviter la .recherche avec obj.hasOwnProperty('key')etObject.getOwnPropertyNames(f)


3) Il existe deux façons principales de définir obj.__proto__:

  • new:

    var F = function() {}
    var f = new F()

    a ensuite newdéfini:

    f.__proto__ === F.prototype

    C'est là que .prototypes'habitue.

  • Object.create:

     f = Object.create(proto)

    ensembles:

    f.__proto__ === proto

4) Le code:

var F = function(i) { this.i = i }
var f = new F(1)

Correspond au schéma suivant (certains Numberéléments sont omis):

(Function)       (  F  )                                      (f)----->(1)
 |  ^             | | ^                                        |   i    |
 |  |             | | |                                        |        |
 |  |             | | +-------------------------+              |        |
 |  |constructor  | |                           |              |        |
 |  |             | +--------------+            |              |        |
 |  |             |                |            |              |        |
 |  |             |                |            |              |        |
 |[[Prototype]]   |[[Prototype]]   |prototype   |constructor   |[[Prototype]]
 |  |             |                |            |              |        |
 |  |             |                |            |              |        |
 |  |             |                | +----------+              |        |
 |  |             |                | |                         |        |
 |  |             |                | | +-----------------------+        |
 |  |             |                | | |                                |
 v  |             v                v | v                                |
(Function.prototype)              (F.prototype)                         |
 |                                 |                                    |
 |                                 |                                    |
 |[[Prototype]]                    |[[Prototype]]          [[Prototype]]|
 |                                 |                                    |
 |                                 |                                    |
 | +-------------------------------+                                    |
 | |                                                                    |
 v v                                                                    v
(Object.prototype)                                       (Number.prototype)
 | | ^
 | | |
 | | +---------------------------+
 | |                             |
 | +--------------+              |
 |                |              |
 |                |              |
 |[[Prototype]]   |constructor   |prototype
 |                |              |
 |                |              |
 |                | -------------+
 |                | |
 v                v |
(null)           (Object)

Ce diagramme montre de nombreux nœuds d'objets prédéfinis en langage:

  • null
  • Object
  • Object.prototype
  • Function
  • Function.prototype
  • 1
  • Number.prototype(peut être trouvé avec (1).__proto__, parenthèse obligatoire pour satisfaire la syntaxe)

Nos 2 lignes de code n'ont créé que les nouveaux objets suivants:

  • f
  • F
  • F.prototype

iest maintenant une propriété de fparce que lorsque vous faites:

var f = new F(1)

il évalue Fà thisêtre la valeur qui newretournera, qui sera alors assignée à f.


5) .constructor provient normalement de F.prototypela .recherche:

f.constructor === F
!f.hasOwnProperty('constructor')
Object.getPrototypeOf(f) === F.prototype
F.prototype.hasOwnProperty('constructor')
F.prototype.constructor === f.constructor

Lorsque nous écrivons f.constructor, JavaScript effectue la .recherche comme suit :

  • f n'a pas .constructor
  • f.__proto__ === F.prototypea .constructor === F, alors prenez-le

Le résultat f.constructor == Fest intuitivement correct, puisqu'il Fest utilisé pour construire f, par exemple, des champs définis, un peu comme dans les langages OOP classiques.


6) La syntaxe d'héritage classique peut être obtenue en manipulant des chaînes de prototypes.

ES6 ajoute les mots clés classet extends, qui sont principalement du sucre de syntaxe pour une folie de manipulation de prototype auparavant possible.

class C {
    constructor(i) {
        this.i = i
    }
    inc() {
        return this.i + 1
    }
}

class D extends C {
    constructor(i) {
        super(i)
    }
    inc2() {
        return this.i + 2
    }
}
// Inheritance syntax works as expected.
c = new C(1)
c.inc() === 2
(new D(1)).inc() === 2
(new D(1)).inc2() === 3
// "Classes" are just function objects.
C.constructor === Function
C.__proto__ === Function.prototype
D.constructor === Function
// D is a function "indirectly" through the chain.
D.__proto__ === C
D.__proto__.__proto__ === Function.prototype
// "extends" sets up the prototype chain so that base class
// lookups will work as expected
var d = new D(1)
d.__proto__ === D.prototype
D.prototype.__proto__ === C.prototype
// This is what `d.inc` actually does.
d.__proto__.__proto__.inc === C.prototype.inc
// Class variables
// No ES6 syntax sugar apparently:
// http://stackoverflow.com/questions/22528967/es6-class-variable-alternatives
C.c = 1
C.c === 1
// Because `D.__proto__ === C`.
D.c === 1
// Nothing makes this work.
d.c === undefined

Diagramme simplifié sans tous les objets prédéfinis:

(c)----->(1)
 |   i
 |
 |
 |[[Prototype]]
 |
 |
 v    __proto__
(C)<--------------(D)         (d)
| |                |           |
| |                |           |
| |prototype       |prototype  |[[Prototype]] 
| |                |           |
| |                |           |
| |                | +---------+
| |                | |
| |                | |
| |                v v
|[[Prototype]]    (D.prototype)--------> (inc2 function object)
| |                |             inc2
| |                |
| |                |[[Prototype]]
| |                |
| |                |
| | +--------------+
| | |
| | |
| v v
| (C.prototype)------->(inc function object)
|                inc
v
Function.prototype

Prenons un moment pour étudier le fonctionnement des éléments suivants:

c = new C(1)
c.inc() === 2

Les premiers ensembles de ligne c.ià 1comme expliqué dans « 4) ».

Sur la deuxième ligne, lorsque nous faisons:

c.inc()
  • .incse trouve à travers la [[Prototype]]chaîne: c-> C-> C.prototype->inc
  • lorsque nous appelons une fonction en Javascript as X.Y(), JavaScript est automatiquement thiségal Xà l'intérieur de l' Y()appel de fonction!

La même logique exacte explique également d.incet d.inc2.

Cet article https://javascript.info/class#not-just-a-syntax-sugar mentionne d'autres effets classà savoir. Certains d'entre eux ne seraient pas réalisables sans le classmot - clé (TODO check which):

Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功
la source
1
@tomasb merci! "Je ne sais pas où vous avez trouvé ceci": après avoir vu quelques-uns de ces langages dynamiques, j'ai remarqué que ce qui compte le plus dans leur système de classe est le fonctionnement de la .recherche (et le nombre de copies des données effectuées) . Je me suis donc mis à comprendre ce point. Le reste est Google + articles de blog + un interprète Js à portée de main. :)
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功
1
Je ne comprends toujours pas pourquoi g.constructor === Object parce que vous avez dit que "4) Lorsque vous faites f = new F, new définit également f.constructor = F". Pourriez-vous m'expliquer davantage? Quoi qu'il en soit, c'est la meilleure réponse que je recherche. Merci beaucoup!
nguyenngoc101
@ nguyenngoc101 merci! La sets f.constructor = Fpartie était manifestement erronée et contredite par d'autres sections: .constructoron la trouve grâce à la .recherche sur la chaîne du prototype. Fixé maintenant.
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功
de toute la discussion ce que j'obtiens (provient de l'héritage classique) si je crée une fonction constructeur et essaie d'en créer une instance en utilisant un nouvel opérateur, j'obtiendrai seulement les méthodes et les propriétés qui étaient attachées à l'objet proto, donc il est nécessaire d'attacher toute la méthode et les propriétés à proto objet si nous voulons hériter, mi à droite?
blackHawk
1
@CiroSantilli 刘晓波 死 六四 事件 法轮功 Je ne pense pas que ce soit un bug dans Chromium. Je pense que c'est juste un symptôme à partir duquel fle prototype n'est défini Fqu'au moment de la construction; fne saura ni ne se souciera F.prototypeà aucun moment après sa première construction.
John Glassmyer
76

prototypevous permet de faire des cours. si vous ne l'utilisez pas, prototypeil devient statique.

Voici un petit exemple.

var obj = new Object();
obj.test = function() { alert('Hello?'); };

Dans le cas ci-dessus, vous avez un test d'appel de fonction statique. Cette fonction n'est accessible que par obj.test où vous pouvez imaginer obj comme une classe.

où comme dans le code ci-dessous

function obj()
{
}

obj.prototype.test = function() { alert('Hello?'); };
var obj2 = new obj();
obj2.test();

L'obj est devenu une classe qui peut maintenant être instanciée. Plusieurs instances d'obj peuvent exister et elles ont toutestest fonction.

Ce qui précède est ma compréhension. J'en fais un wiki communautaire, donc les gens peuvent me corriger si je me trompe.

Ramesh
la source
13
-1: prototypeest une propriété des fonctions constructeurs, pas des instances, c'est-à-dire que votre code est incorrect! Peut-être que vous vouliez dire la propriété non standard __proto__des objets, mais c'est une bête complètement différente ...
Christoph
@Christoph - Merci de l'avoir signalé. J'ai mis à jour l'exemple de code.
Ramesh
3
Il y a tellement plus ... De plus, JavaScript n'est pas un langage basé sur des classes - il traite de l'héritage via des prototypes, vous devez couvrir les différences plus en détail!
James
5
Je pense que cette réponse est un peu erronée.
Armin Cifuentes
Peut-être que la réponse est «erronée», mais explique à quoi sert le prototype et maintenant tout est clair pour moi, après toutes ces «réponses» avec des centaines de votes «positifs». Je vous remercie.
Aleks
66

Après avoir lu ce fil, je me sens confus avec JavaScript Prototype Chain, puis j'ai trouvé ces graphiques

http://iwiki.readthedocs.org/en/latest/javascript/js_core.html#inheritance * [[protytype]] * et <code> prototype </code> propriété des objets fonction

c'est un tableau clair pour montrer l'héritage JavaScript par chaîne de prototype

et

http://www.javascriptbank.com/javascript/article/JavaScript_Classical_Inheritance/

celui-ci contient un exemple avec du code et plusieurs jolis diagrammes.

la chaîne de prototype retombe finalement sur Object.prototype.

La chaîne de prototype peut être techniquement étendue aussi longtemps que vous le souhaitez, à chaque fois en définissant le prototype de la sous-classe égal à un objet de la classe parente.

J'espère qu'il vous sera également utile de comprendre la chaîne de prototypes JavaScript.

rockXrock
la source
Est-il possible d'avoir plusieurs héritages sur Javascript?
Foo est-il un objet littéral ici ou un objet fonction? Si c'est un objet littéral, je crois que Foo.prototype ne pointera pas vers Foo via le constructeur.
Madhur Ahuja
@ user3376708 JavaScript ne prend en charge que l'héritage unique ( source )
Rafael Eyng
@ Nuno_147 Ce n'est pas clair au début, mais si vous regardez assez longtemps, vous pourriez en tirer quelque chose.
marcelocra
3
Pouvez-vous expliquer ce que cela [[Prototype]]signifie?
CodyBugstein
40

Chaque objet a une propriété interne, [[Prototype]] , le liant à un autre objet:

object [[Prototype]]  anotherObject

En javascript traditionnel, l'objet lié est la prototypepropriété d'une fonction:

object [[Prototype]]  aFunction.prototype

Certains environnements exposent [[Prototype]] comme __proto__:

anObject.__proto__ === anotherObject

Vous créez le lien [[Prototype]] lors de la création d'un objet.

// (1) Object.create:
var object = Object.create(anotherObject)
// object.__proto__ = anotherObject

// (2) ES6 object initializer:
var object = { __proto__: anotherObject };
// object.__proto__ = anotherObject

// (3) Traditional JavaScript:
var object = new aFunction;
// object.__proto__ = aFunction.prototype

Ces déclarations sont donc équivalentes:

var object = Object.create(Object.prototype);
var object = { __proto__: Object.prototype }; // ES6 only
var object = new Object;

Vous ne pouvez pas réellement voir le lien target ( Object.prototype) dans une nouvelle instruction; à la place, la cible est impliquée par le constructeur (Object ).

Rappelles toi:

  • Chaque objet a un lien, [[Prototype]] , parfois exposé comme __proto__ .
  • Chaque fonction a une prototypepropriété, contenant initialement un objet vide.
  • Les objets créés avec new sont liés à la prototypepropriété de leur constructeur.
  • Si une fonction n'est jamais utilisée comme constructeur, sa prototypepropriété ne sera pas utilisée.
  • Si vous n'avez pas besoin d'un constructeur, utilisez Object.create au lieu de new.
sam
la source
1
La révision 5 a supprimé certaines informations utiles, notamment des informations sur Object.create (). Voir révision 4 .
Palec
@Palec que dois-je ajouter?
sam
2
IMO au moins le lien vers les Object.create()documents , @sam. Des liens vers __proto__et Object.prototypeseraient de belles améliorations. Et j'ai aimé vos exemples de la façon dont les prototypes fonctionnent avec les constructeurs et Object.create(), mais ils étaient probablement la partie longue et moins pertinente dont vous vouliez vous débarrasser.
Palec
de toute la discussion ce que j'obtiens (provient de l'héritage classique) si je crée une fonction constructeur et essaie d'en créer une instance en utilisant un nouvel opérateur, j'obtiendrai seulement les méthodes et les propriétés qui étaient attachées à l'objet proto, donc il est nécessaire d'attacher toute la méthode et les propriétés à proto objet si nous voulons hériter, mi à droite?
blackHawk
29

Javascript n'a pas d'héritage au sens habituel, mais il a la chaîne prototype.

chaîne prototype

Si un membre d'un objet est introuvable dans l'objet, il le recherche dans la chaîne de prototypes. La chaîne se compose d'autres objets. Le prototype d'une instance donnée est accessible avec le__proto__ variable. Chaque objet en a un, car il n'y a pas de différence entre les classes et les instances en javascript.

L'avantage d'ajouter une fonction / variable au prototype est qu'elle ne doit être en mémoire qu'une seule fois, pas pour chaque instance.

Il est également utile pour l'héritage, car la chaîne de prototype peut se composer de nombreux autres objets.

Georg Schölly
la source
1
FF et Chrome prennent en charge proto , mais pas IE ni Opera.
certains
Georg, veuillez clarifier pour un noob - "il n'y a pas de différence entre les classes et les instances en javascript." - pourriez-vous élaborer? Comment cela marche-t-il?
Hamish Grubijan
de toute la discussion ce que j'obtiens (provient de l'héritage classique) si je crée une fonction constructeur et essaie d'en créer une instance en utilisant un nouvel opérateur, j'obtiendrai seulement les méthodes et les propriétés qui étaient attachées à l'objet proto, donc il est nécessaire d'attacher toute la méthode et les propriétés à proto objet si nous voulons hériter, mi à droite?
blackHawk
28

Cet article est long. Mais je suis sûr que cela effacera la plupart de vos questions concernant la nature "prototypique" de l'héritage JavaScript. Et encore plus. Veuillez lire l'article complet.

JavaScript a essentiellement deux types de types de données

  • Non objets
  • Objets

Non objets

Voici les types de données non objet

  • chaîne
  • nombre (y compris NaN et Infinity)
  • valeurs booléennes (vrai, faux)
  • indéfini

Ces types de données renvoient la suite lorsque vous utilisez l' opérateur typeof

Type de "string literal" (ou une variable contenant string literal) === 'string'

typeof 5 (ou tout littéral numérique ou une variable contenant un littéral numérique ou NaN ou Infynity ) === 'nombre'

typeof true (ou false ou une variable contenant true ou false ) === 'booléen'

typeof undefined (ou une variable non définie ou une variable contenant undefined ) === 'indéfini'

Les types de données chaîne , nombre et booléen peuvent être représentés à la fois en tant qu'objets et non objets . Lorsqu'ils sont représentés en tant qu'objets, leur type est toujours === 'objet'. Nous y reviendrons une fois que nous aurons compris les types de données d'objet.

Objets

Les types de données d'objet peuvent être divisés en deux types

  1. Objets de type fonction
  2. Objets de type non fonction

Les objets de type Function sont ceux qui renvoient la chaîne 'function' avec l' opérateur typeof . Toutes les fonctions définies par l'utilisateur et tous les objets JavaScript intégrés qui peuvent créer de nouveaux objets à l'aide d'un nouvel opérateur entrent dans cette catégorie. Par exemple.

  • Objet
  • Chaîne
  • Nombre
  • Booléen
  • Array
  • Tableaux typés
  • RegExp
  • Une fonction
  • Tous les autres objets intégrés qui peuvent créer de nouveaux objets en utilisant un nouvel opérateur
  • function UserDefinedFunction () {/ * code défini par l'utilisateur * /}

Donc, typeof (Object) === typeof (String) === typeof (Number) === typeof (Boolean) === typeof (Array) === typeof (RegExp) === typeof (Function) == = typeof (UserDefinedFunction) === 'fonction'

Tous les objets de type Function sont en fait des instances de la fonction d' objet JavaScript intégrée (y compris l' objet Function , c'est-à-dire qu'il est défini de manière récursive). C'est comme si ces objets avaient été définis de la manière suivante

var Object= new Function ([native code for object Object])
var String= new Function ([native code for object String])
var Number= new Function ([native code for object Number])
var Boolean= new Function ([native code for object Boolean])
var Array= new Function ([native code for object Array])
var RegExp= new Function ([native code for object RegExp])
var Function= new Function ([native code  for object Function])
var UserDefinedFunction= new Function ("user defined code")

Comme mentionné, les objets de type Function peuvent en outre créer de nouveaux objets à l'aide du nouvel opérateur . Par exemple, un objet de type Object , String , Number , Boolean , Array , RegExp ou UserDefinedFunction peut être créé en utilisant

var a=new Object() or var a=Object() or var a={} //Create object of type Object
var a=new String() //Create object of type String
var a=new Number() //Create object of type Number
var a=new Boolean() //Create object of type Boolean
var a=new Array() or var a=Array() or var a=[]  //Create object of type Array
var a=new RegExp() or var a=RegExp() //Create object of type RegExp
var a=new UserDefinedFunction() 

Les objets ainsi créés sont tous des objets de type Non Fonction et renvoient leur typeof === 'objet' . Dans tous ces cas, l'objet "a" ne peut plus créer d'objets en utilisant l'opérateur new. Donc, ce qui suit est faux

var b=new a() //error. a is not typeof==='function'

L'objet Math intégré est typeof === 'objet' . Par conséquent, un nouvel objet de type Math ne peut pas être créé par un nouvel opérateur.

var b=new Math() //error. Math is not typeof==='function'

Notez également que les fonctions Object , Array et RegExp peuvent créer un nouvel objet sans même utiliser l' opérateur new . Mais ceux qui suivent ne le font pas.

var a=String() // Create a new Non Object string. returns a typeof==='string' 
var a=Number() // Create a new Non Object Number. returns a typeof==='number'
var a=Boolean() //Create a new Non Object Boolean. returns a typeof==='boolean'

Les fonctions définies par l'utilisateur sont des cas particuliers.

var a=UserDefinedFunction() //may or may not create an object of type UserDefinedFunction() based on how it is defined.

Étant donné que les objets de type Function peuvent créer de nouveaux objets, ils sont également appelés constructeurs .

Chaque constructeur / fonction (qu'il soit intégré ou défini par l'utilisateur) lorsqu'il est défini automatiquement possède une propriété appelée "prototype" dont la valeur par défaut est définie en tant qu'objet. Cet objet lui-même possède une propriété appelée "constructeur" qui, par défaut, fait référence au constructeur / fonction .

Par exemple, lorsque nous définissons une fonction

function UserDefinedFunction()
{
}

suit automatiquement

UserDefinedFunction.prototype={constructor:UserDefinedFunction}

Cette propriété "prototype" n'est présente que dans les objets de type Function (et jamais dans les objets de type Non Function ).

En effet, lorsqu'un nouvel objet est créé (à l'aide d'un nouvel opérateur), il hérite de toutes les propriétés et méthodes de l'objet prototype actuel de la fonction constructeur, c'est-à-dire qu'une référence interne est créée dans l'objet nouvellement créé qui fait référence à l'objet référencé par l'objet prototype actuel de la fonction constructeur.

Cette "référence interne" qui est créée dans l'objet pour référencer les propriétés héritées est connue sous le nom de prototype de l' objet (qui référence l'objet référencé par la propriété "prototype" du constructeur mais qui en est différent). Pour tout objet (fonction ou non fonction), cela peut être récupéré à l'aide de Object.getPrototypeOf () méthode . En utilisant cette méthode, on peut tracer la chaîne prototype d'un objet.

De plus, chaque objet créé ( type Function ou type Non Function ) possède une propriété "constructeur" héritée de l'objet référencé par la propriété prototype de la fonction Constructeur. Par défaut, cette propriété "constructeur" fait référence à la fonction constructeur qui l'a créée (si le "prototype" par défaut de la fonction constructeur n'est pas modifié).

Pour tous les objets de type Function, la fonction constructeur est toujours la fonction Function () {}

Pour les objets de type Non Function (par exemple Javascript Built in Math object), la fonction constructeur est la fonction qui l'a créée. Pour l' objet Math , il s'agit de la fonction Object () {} .

Tout le concept expliqué ci-dessus peut être un peu intimidant à comprendre sans aucun code de support. Veuillez parcourir le code suivant ligne par ligne pour comprendre le concept. Essayez de l'exécuter pour avoir une meilleure compréhension.

function UserDefinedFunction()
{ 

} 

/* creating the above function automatically does the following as mentioned earlier

UserDefinedFunction.prototype={constructor:UserDefinedFunction}

*/


var newObj_1=new UserDefinedFunction()

alert(Object.getPrototypeOf(newObj_1)===UserDefinedFunction.prototype)  //Displays true

alert(newObj_1.constructor) //Displays function UserDefinedFunction

//Create a new property in UserDefinedFunction.prototype object

UserDefinedFunction.prototype.TestProperty="test"

alert(newObj_1.TestProperty) //Displays "test"

alert(Object.getPrototypeOf(newObj_1).TestProperty)// Displays "test"

//Create a new Object

var objA = {
        property1 : "Property1",
        constructor:Array

}


//assign a new object to UserDefinedFunction.prototype
UserDefinedFunction.prototype=objA

alert(Object.getPrototypeOf(newObj_1)===UserDefinedFunction.prototype)  //Displays false. The object referenced by UserDefinedFunction.prototype has changed

//The internal reference does not change
alert(newObj_1.constructor) // This shall still Display function UserDefinedFunction

alert(newObj_1.TestProperty) //This shall still Display "test" 

alert(Object.getPrototypeOf(newObj_1).TestProperty) //This shall still Display "test"


//Create another object of type UserDefinedFunction
var newObj_2= new UserDefinedFunction();

alert(Object.getPrototypeOf(newObj_2)===objA) //Displays true.

alert(newObj_2.constructor) //Displays function Array()

alert(newObj_2.property1) //Displays "Property1"

alert(Object.getPrototypeOf(newObj_2).property1) //Displays "Property1"

//Create a new property in objA
objA.property2="property2"

alert(objA.property2) //Displays "Property2"

alert(UserDefinedFunction.prototype.property2) //Displays "Property2"

alert(newObj_2.property2) // Displays Property2

alert(Object.getPrototypeOf(newObj_2).property2) //Displays  "Property2"

La chaîne prototype de chaque objet remonte finalement à Object.prototype (qui lui-même n'a pas d'objet prototype). Le code suivant peut être utilisé pour tracer la chaîne prototype d'un objet

var o=Starting object;

do {
    alert(o + "\n" + Object.getOwnPropertyNames(o))

}while(o=Object.getPrototypeOf(o))

La chaîne de prototype pour divers objets fonctionne comme suit.

  • Chaque objet Function (y compris l'objet Function intégré) -> Function.prototype -> Object.prototype -> null
  • Objets simples (créés par un nouvel objet () ou {} y compris un objet Math intégré) -> Object.prototype -> null
  • Objet créé avec new ou Object.create -> Une ou plusieurs chaînes de prototypes -> Object.prototype -> null

Pour créer un objet sans aucun prototype, utilisez ce qui suit:

var o=Object.create(null)
alert(Object.getPrototypeOf(o)) //Displays null

On pourrait penser que la définition de la propriété prototype du constructeur sur null crée un objet avec un prototype nul. Cependant, dans de tels cas, le prototype de l'objet nouvellement créé est défini sur Object.prototype et son constructeur est défini sur Function Object. Cela est démontré par le code suivant

function UserDefinedFunction(){}
UserDefinedFunction.prototype=null// Can be set to any non object value (number,string,undefined etc.)

var o=new UserDefinedFunction()
alert(Object.getPrototypeOf(o)==Object.prototype)   //Displays true
alert(o.constructor)    //Displays Function Object

Suite dans le résumé de cet article

  • Il existe deux types d'objets Types de fonction et Types de non-fonction
  • Seuls les objets de type Function peuvent créer un nouvel objet à l'aide de l' opérateur new . Les objets ainsi créés sont des objets de type Non Fonction . Les objets de type Non Fonction ne peuvent plus créer un objet à l'aide de l' opérateur new .

  • Par défaut, tous les objets de type Function ont une propriété "prototype" . Cette propriété "prototype" fait référence à un objet qui a une propriété "constructeur" qui par défaut fait référence à l' objet de type Function lui-même.

  • Tous les objets ( type Function et type Non Function ) ont une propriété "constructeur" qui par défaut fait référence à l' objet / constructeur de type Function qui l'a créé.

  • Chaque objet créé en interne fait référence à l'objet référencé par la propriété "prototype" du constructeur qui l'a créé. Cet objet est connu sous le nom de prototype de l'objet créé (qui est différent de la propriété "prototype" des objets de type Function qu'il référence). De cette façon, l'objet créé peut accéder directement aux méthodes et propriétés définies dans l'objet référencé par la propriété "prototype" du Constructeur (au moment de la création de l'objet).

  • Le prototype d' un objet (et donc ses noms de propriété hérités) peut être récupéré à l'aide de la méthode Object.getPrototypeOf () . En fait, cette méthode peut être utilisée pour parcourir toute la chaîne de prototypes de l'objet.

  • La chaîne de prototypes de chaque objet remonte finalement à Object.prototype (à moins que l'objet ne soit créé en utilisant Object.create (null) auquel cas l'objet n'a pas de prototype).

  • typeof (new Array ()) === 'object' est par conception du langage et non une erreur comme l'a souligné Douglas Crockford

  • La définition de la propriété prototype du constructeur sur null (ou non défini, nombre, vrai, faux, chaîne) ne doit pas créer un objet avec un prototype nul. Dans de tels cas, le prototype de l'objet nouvellement créé est défini sur Object.prototype et son constructeur est défini sur Function Object.

J'espère que cela t'aides.

Arup Hore
la source
24

Le concept d' prototypalhéritage est l'un des plus compliqués pour de nombreux développeurs. Essayons de comprendre la racine du problème pour prototypal inheritancemieux comprendre . Commençons par une plainfonction.

entrez la description de l'image ici

Si nous utilisons un newopérateur sur le Tree function, nous l'appelons en constructorfonction.

entrez la description de l'image ici

Chaque JavaScriptfonction a un prototype. Lorsque vous vous connectez Tree.prototype, vous obtenez ...

entrez la description de l'image ici

Si vous regardez la console.log()sortie ci-dessus , vous pourriez voir une propriété constructeur Tree.prototypeet une __proto__propriété aussi. Le __proto__représente le sur prototypelequel cela functionest basé, et comme il s'agit simplement d'un simple JavaScript functionsans inheritanceconfiguration, il fait référence au Object prototypequi est quelque chose qui vient d'être intégré à JavaScript ...

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

Cela a des choses comme .toString, .toValue, .hasOwnPropertyetc ...

__proto__qui a été apporté mon mozilla est obsolète et est remplacé par une Object.getPrototypeOfméthode pour obtenir le object's prototype.

entrez la description de l'image ici

Object.getPrototypeOf(Tree.prototype); // Object {} 

Ajoutons une méthode à notre Tree prototype.

entrez la description de l'image ici

Nous avons modifié le Rootet y avons ajouté une functionbranche.

entrez la description de l'image ici

Cela signifie que lorsque vous créez un instancede Tree, vous pouvez appeler sa branchméthode.

entrez la description de l'image ici

Nous pouvons également ajouter primitivesou objectsà notre Prototype.

entrez la description de l'image ici

Ajoutons un child-treeà notre Tree.

entrez la description de l'image ici

Ici, l' Childhéritage prototypede Tree, ce que nous faisons ici est d'utiliser une Object.create()méthode pour créer un nouvel objet basé sur ce que vous passez, le voici Tree.prototype. Dans ce cas, ce que nous faisons est de définir le prototype de Child sur un nouvel objet qui semble identique au Treeprototype. Ensuite, nous définissons le Child's constructor to Child, sinon, cela indiquerait Tree().

entrez la description de l'image ici

Childa maintenant le sien prototype, ses __proto__points vers Treeet les Tree's prototypepoints vers la base Object.

Child  
|
 \
  \
   Tree.prototype
   - branch
   |
   |
    \
     \
      Object.prototype
      -toString
      -valueOf
      -etc., etc.

Maintenant , vous créez un instancede Childet appel branchqui est à l' origine disponible Tree. Nous n'avons pas réellement défini notre branchsur le Child prototype. MAIS, dans Root prototypelequel l'enfant hérite.

entrez la description de l'image ici

Dans JS, tout n'est pas un objet, tout peut agir comme un objet.

Javascripta des primitives comme strings, number, booleans, undefined, null.ils ne le sont pas object(i.e reference types), mais peut certainement agir comme un object. Regardons un exemple ici.

entrez la description de l'image ici

Dans la première ligne de cette liste, une primitivevaleur de chaîne est affectée au nom. La deuxième ligne traite le nom comme un objectet appelle en charAt(0)utilisant la notation par points.

Voici ce qui se passe dans les coulisses: // ce que fait le JavaScriptmoteur

entrez la description de l'image ici

Il String objectn'existe que pour une seule instruction avant d'être détruite (un processus appelé autoboxing). Revenons à nouveau à notre prototypal inheritance.

  • Javascriptprend en charge l'héritage via delegationbasé sur prototypes.
  • Chacun Functiona une prototypepropriété, qui fait référence à un autre objet.
  • properties/functionssont regardés de objectlui - même ou via une prototypechaîne s'il n'existe pas

Un prototypedans JS est un objet que yieldsvous au parent d'un autre object. [c.-à-d. délégation] Delegation signifie que si vous ne pouvez pas faire quelque chose, vous direz à quelqu'un d'autre de le faire pour vous.

entrez la description de l'image ici

https://jsfiddle.net/say0tzpL/1/

Si vous recherchez le violon ci-dessus, le chien a accès à la toStringméthode, mais elle n'est pas disponible, mais disponible via la chaîne de prototype qui délègue àObject.prototype

entrez la description de l'image ici

Si vous regardez celui ci-dessous, nous essayons d'accéder à la callméthode qui est disponible dans chaque function.

entrez la description de l'image ici

https://jsfiddle.net/rknffckc/

Si vous recherchez le violon ci-dessus, ProfileFunction a accès à la callméthode, mais elle n'est pas disponible dedans, mais disponible via la chaîne de prototype qui délègue àFunction.prototype

entrez la description de l'image ici

Remarque: prototype est une propriété du constructeur de la fonction, tandis que __proto__est une propriété des objets construits à partir du constructeur de la fonction. Chaque fonction est livrée avec une prototypepropriété dont la valeur est vide object. Lorsque nous créons une instance de la fonction, nous obtenons une propriété interne [[Prototype]]ou __proto__dont la référence est le prototype de la fonction constructor.

entrez la description de l'image ici

Le diagramme ci-dessus semble un peu compliqué, mais fait ressortir toute l'image sur la façon dont prototype chaining fonctionnement. Voyons cela lentement:

Il y a deux instances b1et b2, dont le constructeur est Baret parent est Foo et a deux méthodes à partir de la chaîne de prototype identifyet speakvia BaretFoo

entrez la description de l'image ici

https://jsfiddle.net/kbp7jr7n/

Si vous recherchez le code ci-dessus, nous avons un Fooconstructeur qui a la méthode identify()et un Barconstructeur qui a une speakméthode. Nous créons deux Barinstances b1et b2dont le type parent est Foo. Maintenant, tout en appelant la speakméthode de Bar, nous pouvons identifier qui appelle la parole via la prototypechaîne.

entrez la description de l'image ici

Bara maintenant toutes les méthodes Fooqui sont définies dans son prototype. Penchons-nous davantage pour comprendre le Object.prototypeet Function.prototypeet comment ils sont liés. Si vous recherchez le constructeur de Foo, Baret Objectêtes Function constructor.

entrez la description de l'image ici

Le prototypede Barest Foo, prototyped' Fooest - Objectet si vous regardez attentivement le prototypede Fooest lié à Object.prototype.

entrez la description de l'image ici

Avant de terminer, fermons simplement avec un petit morceau de code ici pour résumer tout ce qui précède . Nous utilisons l' instanceofopérateur ici pour vérifier si un objecta dans sa prototypechaîne la prototypepropriété d'un constructorqui résume ci-dessous l'intégralité du grand diagramme.

entrez la description de l'image ici

J'espère que cet ajout contient des informations, je sais que cela pourrait être gros à saisir ... en termes simples, ce ne sont que des objets liés à des objets !!!!

Thalaivar
la source
22

quel est le but exact de cette propriété ".prototype"?

L'interface avec les classes standard devient extensible. Par exemple, vous utilisez la Arrayclasse et vous devez également ajouter un sérialiseur personnalisé pour tous vos objets de tableau. Souhaitez-vous passer du temps à coder une sous-classe, ou utiliser une composition ou ... La propriété prototype résout ce problème en permettant aux utilisateurs de contrôler l'ensemble exact de membres / méthodes disponibles pour une classe.

Considérez les prototypes comme un pointeur de table supplémentaire. Lorsque certains membres manquent dans la classe d'origine, le prototype est recherché lors de l'exécution.

dirkgently
la source
21

Il peut être utile de classer les chaînes prototypes en deux catégories.

Considérez le constructeur:

 function Person() {}

La valeur de Object.getPrototypeOf(Person)est une fonction. En fait, ça l'est Function.prototype. Depuis qu'il a Personété créé en tant que fonction, il partage le même objet fonction prototype que toutes les fonctions. C'est la même chose que Person.__proto__, mais cette propriété ne doit pas être utilisée. Quoi qu'il en soit, avec Object.getPrototypeOf(Person)vous, montez efficacement l'échelle de ce qu'on appelle la chaîne prototype.

La chaîne vers le haut ressemble à ceci:

    PersonFunction.prototypeObject.prototype(point final)

Il est important que cette chaîne prototype ait peu à voir avec les objets qui Personpeuvent être construits . Ces objets construits ont leur propre chaîne prototype, et cette chaîne ne peut potentiellement avoir aucun ancêtre proche en commun avec celui mentionné ci-dessus.

Prenons par exemple cet objet:

var p = new Person();

p n'a pas de relation prototype-chaîne directe avec Personne . Leur relation est différente. L'objet p possède sa propre chaîne prototype. En utilisant Object.getPrototypeOf, vous constaterez que la chaîne est la suivante:

    pPerson.prototypeObject.prototype(point final)

Il n'y a pas d'objet fonction dans cette chaîne (bien que cela puisse l'être).

Il Personsemble donc lié à deux types de chaînes, qui vivent leur propre vie. Pour "sauter" d'une chaîne à l'autre, vous utilisez:

  1. .prototype: saute de la chaîne du constructeur à la chaîne de l'objet créé. Cette propriété n'est donc définie que pour les objets fonction (comme elle newne peut être utilisée que sur les fonctions).

  2. .constructor: saute de la chaîne de l'objet créé à la chaîne du constructeur.

Voici une présentation visuelle des deux chaînes prototypes impliquées, représentées sous forme de colonnes:

entrez la description de l'image ici

Pour résumer:

La prototypepropriété ne donne aucune information sur la chaîne de prototypes du sujet , mais sur les objets créés par le sujet.

Il n'est pas surprenant que le nom de la propriété prototypepuisse prêter à confusion. Il aurait peut-être été plus clair si cette propriété avait été nommée prototypeOfConstructedInstancesou quelque chose dans ce sens.

Vous pouvez aller et venir entre les deux chaînes prototypes:

Person.prototype.constructor === Person

Cette symétrie peut être brisée en affectant explicitement un objet différent au prototype propriété (plus à ce sujet plus tard).

Créer une fonction, obtenir deux objets

Person.prototypeest un objet qui a été créé en même temps que la fonction a Personété créée. Il a Personcomme constructeur, même si ce constructeur ne s'est pas encore exécuté. Donc, deux objets sont créés en même temps:

  1. La fonction Personelle-même
  2. L'objet qui agira comme prototype lorsque la fonction est appelée comme constructeur

Les deux sont des objets, mais ils ont des rôles différents: les objets de fonction construisent , tandis que l'autre objet représente le prototype de tout objet que la fonction va construire. L'objet prototype deviendra le parent de l'objet construit dans sa chaîne de prototypes.

Puisqu'une fonction est également un objet, elle a également son propre parent dans sa propre chaîne prototype, mais rappelez-vous que ces deux chaînes concernent des choses différentes.

Voici quelques égalités qui pourraient aider à saisir le problème - toutes ces impressions true:

function Person() {};

// This is prototype chain info for the constructor (the function object):
console.log(Object.getPrototypeOf(Person) === Function.prototype);
// Step further up in the same hierarchy:
console.log(Object.getPrototypeOf(Function.prototype) === Object.prototype);
console.log(Object.getPrototypeOf(Object.prototype) === null);
console.log(Person.__proto__ === Function.prototype);
// Here we swap lanes, and look at the constructor of the constructor
console.log(Person.constructor === Function);
console.log(Person instanceof Function);

// Person.prototype was created by Person (at the time of its creation)
// Here we swap lanes back and forth:
console.log(Person.prototype.constructor === Person);
// Although it is not an instance of it:
console.log(!(Person.prototype instanceof Person));
// Instances are objects created by the constructor:
var p = new Person();
// Similarly to what was shown for the constructor, here we have
// the same for the object created by the constructor:
console.log(Object.getPrototypeOf(p) === Person.prototype);
console.log(p.__proto__ === Person.prototype);
// Here we swap lanes, and look at the constructor
console.log(p.constructor === Person);
console.log(p instanceof Person);

Ajout de niveaux à la chaîne de prototypes

Bien qu'un objet prototype soit créé lorsque vous créez une fonction constructeur, vous pouvez ignorer cet objet et attribuer un autre objet qui devrait être utilisé comme prototype pour toutes les instances suivantes créées par ce constructeur.

Par exemple:

function Thief() { }
var p = new Person();
Thief.prototype = p; // this determines the prototype for any new Thief objects:
var t = new Thief();

Maintenant, la chaîne prototype de t est un pas plus longue que celle de p :

    tpPerson.prototypeObject.prototype(point final)

L'autre chaîne prototype n'est plus: Thiefet Personles frères et sœurs partagent le même parent dans leur chaîne prototype:

    Person}
    Thief  } → Function.prototypeObject.prototype(point final)

Le graphique présenté précédemment peut ensuite être étendu à ceci (l'original Thief.prototypeest omis):

entrez la description de l'image ici

Les lignes bleues représentent des chaînes prototypes, les autres lignes colorées représentent d'autres relations:

  • entre un objet et son constructeur
  • entre un constructeur et l'objet prototype qui sera utilisé pour construire des objets
trincot
la source
16

J'ai trouvé utile d'expliquer la "chaîne prototype" comme convention récursive lorsqu'elle obj_n.prop_Xest référencée:

s'il obj_n.prop_Xn'existe pas, vérifiez obj_n+1.prop_Xobj_n+1 = obj_n.[[prototype]]

Si le prop_Xest finalement trouvé dans le k-ème objet prototype,

obj_1.prop_X = obj_1.[[prototype]].[[prototype]]..(k-times)..[[prototype]].prop_X

Vous pouvez trouver un graphique de la relation des objets Javascript par leurs propriétés ici:

graphique des objets js

http://jsobjects.org

BM
la source
14

Lorsqu'un constructeur crée un objet, cet objet fait implicitement référence à la propriété «prototype» du constructeur dans le but de résoudre les références de propriété. La propriété «prototype» du constructeur peut être référencée par l'expression de programme constructor.prototype, et les propriétés ajoutées au prototype d'un objet sont partagées, par héritage, par tous les objets partageant le prototype.

À M
la source
11

Il y a deux entités distinctes mais liées ici qui doivent être expliquées:

  • La .prototypepropriété des fonctions.
  • La propriété [[Prototype]][1] de tous les objets [2] .

Ce sont deux choses différentes.

La [[Prototype]]propriété:

Il s'agit d'une propriété qui existe sur tous les objets [2] .

Ce qui est stocké ici est un autre objet qui, en tant qu'objet lui-même, a un [[Prototype]]objet qui pointe vers un autre objet. Cet autre objet a [[Prototype]]son propre. Cette histoire se poursuit jusqu'à ce que vous atteigniez l'objet prototypique qui fournit des méthodes accessibles sur tous les objets (comme .toString).

La [[Prototype]]propriété fait partie de ce qui forme la [[Prototype]]chaîne. Cette chaîne d' [[Prototype]]objets est ce qui est examiné lorsque, par exemple, [[Get]]ou les [[Set]]opérations sont effectuées sur un objet:

var obj = {}
obj.a         // [[Get]] consults prototype chain
obj.b = 20    // [[Set]] consults prototype chain

La .prototypepropriété:

Il s'agit d'une propriété qui se trouve uniquement sur les fonctions. En utilisant une fonction très simple:

function Bar(){};

La .prototypepropriété contient un objet auquel vous serez affecté b.[[Prototype]]lorsque vous le ferez var b = new Bar. Vous pouvez facilement examiner ceci:

// Both assign Bar.prototype to b1/b2[[Prototype]]
var b = new Bar;
// Object.getPrototypeOf grabs the objects [[Prototype]]
console.log(Object.getPrototypeOf(b) === Bar.prototype) // true

L'un des plus importants .prototypeest celui de la Objectfonction . Ce prototype contient l'objet prototypique que toutes les [[Prototype]]chaînes contiennent. Sur celui-ci, toutes les méthodes disponibles pour les nouveaux objets sont définies:

// Get properties that are defined on this object
console.log(Object.getOwnPropertyDescriptors(Object.prototype))

Maintenant, puisque .prototypec'est un objet, il a un[[Prototype]] propriété. Lorsque vous n'effectuez aucune affectation à Function.prototype, le .prototype' [[Prototype]]pointe vers l'objet prototypique (Object.prototype ). Cette opération est effectuée automatiquement à chaque fois que vous créez une nouvelle fonction.

De cette façon, chaque fois que vous faites new Bar;la chaîne de prototype est configurée pour vous, vous obtenez tout ce qui est défini surBar.prototype et tout ce qui est défini sur Object.prototype:

var b = new Bar;
// Get all Bar.prototype properties
console.log(b.__proto__ === Bar.prototype)
// Get all Object.prototype properties
console.log(b.__proto__.__proto__ === Object.prototype)

Quand vous faites des missions de maquillage à Function.prototypetout ce que vous faites est l' extension de la chaîne de prototype pour inclure un autre objet. C'est comme une insertion dans une liste liée individuellement.

Cela modifie essentiellement la [[Prototype]] chaîne permettant aux propriétés définies sur l'objet assigné Function.prototypeà être vues par tout objet créé par la fonction.


[1: Cela ne déroutera personne; mis à disposition via la __proto__propriété dans de nombreuses implémentations.
[2]: Tous sauf null.

Dimitris Fasarakis Hilliard
la source
10

Permettez-moi de vous dire ma compréhension des prototypes. Je ne vais pas comparer l'héritage ici avec d'autres langues. Je souhaite que les gens cessent de comparer les langues et comprennent simplement la langue en tant que telle. Comprendre les prototypes et l'héritage prototypique est si simple, comme je vais vous le montrer ci-dessous.

Le prototype est comme un modèle, sur la base duquel vous créez un produit. Le point crucial à comprendre est que lorsque vous créez un objet en utilisant un autre objet comme prototype, le lien entre le prototype et le produit est permanent. Par exemple:

var model = {x:2};
var product = Object.create(model);
model.y = 5;
product.y
=>5

Chaque objet contient une propriété interne appelée [[prototype]], accessible par la Object.getPrototypeOf()fonction. Object.create(model)crée un nouvel objet et définit sa propriété [[prototype]] sur le modèle d' objet . Par conséquent, lorsque vous le ferez Object.getPrototypeOf(product), vous obtiendrez le modèle d' objet .

Les propriétés du produit sont gérées de la manière suivante:

  • Lorsqu'une propriété est accessible pour lire sa valeur, elle est recherchée dans la chaîne de portée. La recherche de la variable commence à partir du produit vers haut jusqu'à son prototype. Si une telle variable est trouvée dans la recherche, la recherche s'arrête juste là et la valeur est retournée. Si une telle variable est introuvable dans la chaîne de portée, undefined est renvoyé.
  • Lorsqu'une propriété est écrite (modifiée), la propriété est toujours écrite sur l' objet produit . Si le produit ne possède pas déjà une telle propriété, il est implicitement créé et écrit.

Une telle liaison d'objets à l'aide de la propriété prototype est appelée héritage prototypique. Là, c'est si simple, d'accord?

Aravind
la source
Pas toujours écrit sur le produit en mission. Vous ne dites pas très clairement que les membres spécifiques à l'instance doivent être initialisés et que les membres partagés peuvent utiliser le prototype. Surtout lorsque vous avez des membres mutables spécifiques à une instance: stackoverflow.com/questions/16063394/…
HMR
HMR: Dans votre exemple dans votre réponse, le ben.food.push ("Hamburger"); line modifie la propriété de l'objet prototype pour les raisons suivantes: 1.) Tout d'abord ben.food est recherché, et toute action de recherche cherchera simplement la chaîne de portée. 2.) La fonction push de cet objet ben.food est exécutée. En écrivant le mode dans ma réponse, je veux dire quand vous lui définissez explicitement une valeur, comme dans: ben.food = ['Idly']; Cela créera toujours une nouvelle propriété (si ce n'est déjà fait) sur l'objet produit, puis lui attribuera la valeur.
Aravind
HMR: Merci pour votre commentaire, cela m'a fait réfléchir et tester ma compréhension.
Aravind
Lors de la réassignation de ben.food, il masquera le membre de la nourriture à moins que la nourriture ne soit créée en utilisant Object.defineProperty, Object.defineProperties ou Object.create avec un deuxième argument (donc pas toujours). Vous pouvez même changer de prototype avec (à quoi ressemble) une réaffectation lorsque vous avez créé un setter getter. En ce qui concerne les modèles d'héritage, je comprends que la fonction constructeur est difficile à comprendre et présente des problèmes majeurs, mais c'est bien si vous la comprenez. L'héritage en JavaScript ne commence et ne se termine pas avec la définition d'un prototype, les initialisations (constructeurs) doivent également être (ré) utilisées.
HMR
Votre réponse est bonne pour expliquer le prototype, mais pourrait être mal interprétée par une simplification excessive de l'héritage dans JavaScript et des membres spécifiques d'instance. De nombreuses questions ont été posées sur la raison pour laquelle la mutation d'un membre prototype sur une instance affecte d'autres instances.
HMR
10

Considérez l' keyValueStoreobjet suivant :

var keyValueStore = (function() {
    var count = 0;
    var kvs = function() {
        count++;
        this.data = {};
        this.get = function(key) { return this.data[key]; };
        this.set = function(key, value) { this.data[key] = value; };
        this.delete = function(key) { delete this.data[key]; };
        this.getLength = function() {
            var l = 0;
            for (p in this.data) l++;
            return l;
        }
    };

    return  { // Singleton public properties
        'create' : function() { return new kvs(); },
        'count' : function() { return count; }
    };
})();

Je peux créer une nouvelle instance de cet objet en procédant comme suit:

kvs = keyValueStore.create();

Chaque instance de cet objet aurait les propriétés publiques suivantes:

  • data
  • get
  • set
  • delete
  • getLength

Supposons maintenant que nous créons 100 instances de cet keyValueStoreobjet. Même si get, set, delete, getLengthfera exactement la même chose pour chacun de ces 100 cas, chaque cas a sa propre copie de cette fonction.

Maintenant, imaginez si vous pouviez avoir une seule get, set, deleteet getLengthcopie, et chaque instance renverrait cette même fonction. Ce serait mieux pour les performances et nécessiterait moins de mémoire.

C'est là que les prototypes entrent en jeu. Un prototype est un «plan directeur» de propriétés héritées mais non copiées par les instances. Cela signifie donc qu'il n'existe qu'une seule fois en mémoire pour toutes les instances d'un objet et qu'il est partagé par toutes ces instances.

Maintenant, considérez à keyValueStorenouveau l' objet. Je pourrais le réécrire comme ceci:

var keyValueStore = (function() {
    var count = 0;
    var kvs = function() {
        count++;
        this.data = {};
    };

    kvs.prototype = {
        'get' : function(key) { return this.data[key]; },
        'set' : function(key, value) { this.data[key] = value; },
        'delete' : function(key) { delete this.data[key]; },
        'getLength' : function() {
            var l = 0;
            for (p in this.data) l++;
            return l;
        }
    };

    return  {
        'create' : function() { return new kvs(); },
        'count' : function() { return count; }
    };
})();

Cela fait exactement la même chose que la version précédente de l' keyValueStoreobjet, sauf que toutes ses méthodes sont maintenant placées dans un prototype. Cela signifie que les 100 instances partagent désormais ces quatre méthodes au lieu d'avoir chacune leur propre copie.

John Slegers
la source
9

Sommaire:

  • Les fonctions sont des objets en javascript et peuvent donc avoir des propriétés
  • Les fonctions (constructeur) ont toujours une propriété prototype
  • Lorsqu'une fonction est utilisée comme constructeur avec le newmot clé, l'objet obtient un prototype. Une référence à ce prototype peut être trouvée sur la __proto__propriété de l'objet nouvellement créé.
  • Cette __proto__propriété fait référence à la prototypepropriété de la fonction constructeur.

Exemple:

function Person (name) {
  this.name = name;
}

let me = new Person('willem');

console.log(Person.prototype) // Person has a prototype property

console.log(Person.prototype === me.__proto__) // the __proto__ property of the instance refers to prototype property of the function.

Pourquoi est-ce utile:

Javascript a un mécanisme lors de la recherche de propriétés sur des objets qui est appelé «héritage prototypique» , voici ce que fait essentiellement:

  • On vérifie d'abord si la propriété se trouve sur l'objet lui-même. Si c'est le cas, cette propriété est retournée.
  • Si la propriété n'est pas située sur l'objet lui-même, elle «grimpera sur le protocole». Il examine essentiellement l'objet auquel fait référence la propriété proto . Là, il vérifie si la propriété est disponible sur l'objet référencé par proto
  • Si la propriété n'est pas située sur l' objet proto , elle grimpera jusqu'à la chaîne proto jusqu'à l'objet Object.
  • S'il ne trouve pas la propriété nulle part sur l'objet et sa chaîne prototype, il retournera indéfini.

Par exemple:

function Person(name) {
  this.name = name;
}

let mySelf = new Person('Willem');

console.log(mySelf.__proto__ === Person.prototype);

console.log(mySelf.__proto__.__proto__ === Object.prototype);

Mise à jour:

La __proto__propriété est obsolète, bien qu'elle soit implémentée dans la plupart des navigateurs modernes, une meilleure façon d'obtenir la référence d'objet prototype serait:

Object.getPrototypeOf()

Willem van der Veen
la source
7

J'aime toujours les analogies quand il s'agit de comprendre ce genre de choses. «L'héritage prototypique» est assez déroutant par rapport à l'héritage de basse de classe à mon avis, même si les prototypes sont un paradigme beaucoup plus simple. En fait avec les prototypes, il n'y a vraiment pas d'héritage, donc le nom en soi trompeur, c'est plutôt un type de «délégation».

Imagine ça ....

Vous êtes au lycée, vous êtes en classe et vous avez un quiz qui doit arriver aujourd'hui, mais vous n'avez pas de stylo pour remplir vos réponses. Ah!

Vous êtes assis à côté de votre ami Finnius, qui pourrait avoir un stylo. Vous demandez, et il regarde autour de son bureau sans succès, mais au lieu de dire "je n'ai pas de stylo", c'est un bon ami qu'il vérifie avec son autre ami Derp s'il a un stylo. Derp a en effet un stylo de rechange et le remet à Finnius, qui vous le remet pour compléter votre quiz. Derp a confié le stylo à Finnius, qui vous a délégué son utilisation.

Ce qui est important ici, c'est que Derp ne vous donne pas le stylo, car vous n'avez pas de relation directe avec lui.

Ceci est un exemple simplifié du fonctionnement des prototypes, dans lequel un arbre de données est recherché pour la chose que vous recherchez.

Louis Moore
la source
3

un autre schéma montrant __proto__ , les relations prototype et constructeur : entrez la description de l'image ici

IvanM
la source
1

C'est juste que vous avez déjà un objet avec Object.newmais vous n'avez toujours pas d'objet lorsque vous utilisez la syntaxe du constructeur.

shiva kumar
la source
1

Il est important de comprendre qu'il existe une distinction entre le prototype d'un objet (qui est disponible via Object.getPrototypeOf(obj)ou via la __proto__propriété obsolète ) et la prototypepropriété sur les fonctions constructeur. Le premier est la propriété de chaque instance et le second est la propriété du constructeur. Autrement dit, se Object.getPrototypeOf(new Foobar())réfère au même objet que Foobar.prototype.

Référence: https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Objects/Object_prototypes

Baraa Al-Tabbaa
la source
0

Le prototype crée un nouvel objet en clonant un objet existant . Donc, vraiment, quand nous pensons au prototype, nous pouvons vraiment penser au clonage ou à la copie de quelque chose au lieu de l'inventer.

Arif
la source