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é.
javascript
dynamic-languages
prototype-oriented
John Leidegren
la source
la source
Réponses:
Chaque objet JavaScript a un "slot" interne appelé
[[Prototype]]
dont la valeur est soitnull
ou anobject
. 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 viaobj.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:new
opérateur (configure la chaîne prototype sur l'objet par défaut renvoyé par une fonction constructeur),extends
mot-clé (configure la chaîne prototype lors de l'utilisation de la syntaxe de classe),Object.create
définira l'argument fourni comme celui[[Prototype]]
de l'objet résultant,Object.getPrototypeOf
etObject.setPrototypeOf
(obtenir / définir l'[[Prototype]]
après création d'objet ), et__proto__
(similaire à 4.)Object.getPrototypeOf
etObject.setPrototypeOf
sont préférés à__proto__
, en partie parce que le comportement deo.__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'
new
opérateur ont une propriété nommée.prototype
en 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
.prototype
tant 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:
... et voici une autre façon:
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:
... l'objet résultant
[[Prototype]]
sera défini sur une instance deParent
, dont[[Prototype]]
, à son tour, estParent.prototype
.Enfin, si vous créez un nouvel objet via
Object.create(foo)
, l'objet résultant[[Prototype]]
sera défini surfoo
.la source
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:
Jusqu'à présent, j'étendais l'objet de base, maintenant je crée un autre objet et puis hérite de Person.
Afficher l'extrait de code
Bien que comme je l'ai dit, je ne peux pas appeler setAmountDue (), getAmountDue () sur une personne.
la source
Customer.prototype = new Person();
ligne, MDN montre un exemple d'utilisationCustomer.prototype = Object.create(Person.prototype)
et indique que «Une erreur courante consiste à utiliser« new Person () »» . la sourceIl 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:
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
this
mot-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
Person
modèle d'objet. mais dans cette étape, je vais essayer de faire exactement la même chose sans utiliser de motprototype
-new
clé .Donc, dans cette étape
functions
,objects
etthis
mot - clé, sont tout ce que nous avons.La première question serait de savoir comment un
this
mot clé pourrait être utile sans utiliser denew
mot clé .Donc pour répondre à cela, disons que nous avons un objet vide, et deux fonctions comme:
et maintenant sans utiliser de
new
mot-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:
dans ce cas, ce serait l'objet de contexte actuel, qui est généralement le global
window
objet dans le navigateur ouGLOBAL
dansNode.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'
person
objet vide , comme:de cette façon, nous pouvons les appeler comme:
et maintenant l'
person
objet est comme:- L'autre façon d'attacher une propriété à un objet est d'utiliser le
prototype
de 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: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 deObject.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: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'
person
objet a été créé (var person = {};
), puis le changer comme:il crée un nouveau JavaScript
Object
et attache lepropertiesObject
à l'__proto__
attribut. Donc, pour vous assurer que vous pouvez faire: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'person
objet.c. JavaScript a une autre façon de fournir la fonction
this
, qui utilise l' appel ou l' application pour appeler la fonction.et
de cette façon qui est ma préférée, nous pouvons facilement appeler nos fonctions comme:
ou
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
.prototype
fonctionnalité. c'est ce que j'utilise pour simuler le processus:dans cette partie, je vais essayer de suivre toutes les étapes que JavaScript prend, sans utiliser le
new
mot - clé etprototype
, lorsque vous utilisez lenew
mot-clé. donc quand nous le faisonsnew Person("George")
, laPerson
fonction 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:
b. l'étape suivante que JavaScript prend consiste à attacher tous les objets prototypes à l'objet nouvellement créé
nous avons
my_person_prototype
ici similaire à l'objet prototype.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:
maintenant nous pouvons appeler la
getName
fonction dans notremy_person_prototype
:c. puis il donne cet objet au constructeur,
nous pouvons le faire avec notre échantillon comme:
ou
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:
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 unObject.prototype
objet:et c'est ainsi que l'héritage fonctionne en JavaScript.
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
.prototype
et il est également possible que cet objet ait son propre prototype interne. etc.la source
__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.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:
Intuitivement, l'héritage classique devrait affecter la recherche de propriété.
2)
__proto__
est utilisé pour la.
recherche de propriété dot comme dansobj.property
..prototype
n'est pas utilisé pour la recherche directement, mais indirectement car il détermine__proto__
lors de la création de l'objet avecnew
.L'ordre de recherche est:
obj
propriétés ajoutées avecobj.p = ...
ouObject.defineProperty(obj, ...)
obj.__proto__
obj.__proto__.__proto__
, etc.__proto__
sontnull
, revenezundefined
.Il s'agit de la soi-disant chaîne prototype .
Vous pouvez éviter la
.
recherche avecobj.hasOwnProperty('key')
etObject.getOwnPropertyNames(f)
3) Il existe deux façons principales de définir
obj.__proto__
:new
:a ensuite
new
défini:C'est là que
.prototype
s'habitue.Object.create
:ensembles:
4) Le code:
Correspond au schéma suivant (certains
Number
éléments sont omis):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
i
est maintenant une propriété def
parce que lorsque vous faites:il évalue
F
àthis
être la valeur quinew
retournera, qui sera alors assignée àf
.5)
.constructor
provient normalement deF.prototype
la.
recherche:Lorsque nous écrivons
f.constructor
, JavaScript effectue la.
recherche comme suit :f
n'a pas.constructor
f.__proto__ === F.prototype
a.constructor === F
, alors prenez-leLe résultat
f.constructor == F
est intuitivement correct, puisqu'ilF
est utilisé pour construiref
, 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
class
etextends
, qui sont principalement du sucre de syntaxe pour une folie de manipulation de prototype auparavant possible.Diagramme simplifié sans tous les objets prédéfinis:
Prenons un moment pour étudier le fonctionnement des éléments suivants:
Les premiers ensembles de ligne
c.i
à1
comme expliqué dans « 4) ».Sur la deuxième ligne, lorsque nous faisons:
.inc
se trouve à travers la[[Prototype]]
chaîne:c
->C
->C.prototype
->inc
X.Y()
, JavaScript est automatiquementthis
égalX
à l'intérieur de l'Y()
appel de fonction!La même logique exacte explique également
d.inc
etd.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 leclass
mot - clé (TODO check which):[[FunctionKind]]:"classConstructor"
, ce qui oblige le constructeur à être appelé avec new: Quelle est la raison pour laquelle les constructeurs de classe ES6 ne peuvent pas être appelés en tant que fonctions normales?Object.defineProperty
.use strict
. Peut être fait avec une expliciteuse strict
pour chaque fonction, ce qui est certes fastidieux.la source
.
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. :)sets f.constructor = F
partie était manifestement erronée et contredite par d'autres sections:.constructor
on la trouve grâce à la.
recherche sur la chaîne du prototype. Fixé maintenant.f
le prototype n'est définiF
qu'au moment de la construction;f
ne saura ni ne se soucieraF.prototype
à aucun moment après sa première construction.prototype
vous permet de faire des cours. si vous ne l'utilisez pas,prototype
il devient statique.Voici un petit exemple.
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
L'obj est devenu une classe qui peut maintenant être instanciée. Plusieurs instances d'obj peuvent exister et elles ont toutes
test
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.
la source
prototype
est 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 ...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
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.
J'espère qu'il vous sera également utile de comprendre la chaîne de prototypes JavaScript.
la source
[[Prototype]]
signifie?Chaque objet a une propriété interne, [[Prototype]] , le liant à un autre objet:
En javascript traditionnel, l'objet lié est la
prototype
propriété d'une fonction:Certains environnements exposent [[Prototype]] comme
__proto__
:Vous créez le lien [[Prototype]] lors de la création d'un objet.
Ces déclarations sont donc équivalentes:
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:
prototype
propriété, contenant initialement un objet vide.prototype
propriété de leur constructeur.prototype
propriété ne sera pas utilisée.new
.la source
Object.create()
documents , @sam. Des liens vers__proto__
etObject.prototype
seraient de belles améliorations. Et j'ai aimé vos exemples de la façon dont les prototypes fonctionnent avec les constructeurs etObject.create()
, mais ils étaient probablement la partie longue et moins pertinente dont vous vouliez vous débarrasser.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.
la source
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
Voici les types de données non objet
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
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.
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
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
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
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.
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.
Les fonctions définies par l'utilisateur sont des cas particuliers.
É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
suit automatiquement
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.
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
La chaîne de prototype pour divers objets fonctionne comme suit.
Pour créer un objet sans aucun prototype, utilisez ce qui suit:
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
Suite dans le résumé de cet article
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.
la source
Le concept d'
prototypal
héritage est l'un des plus compliqués pour de nombreux développeurs. Essayons de comprendre la racine du problème pourprototypal inheritance
mieux comprendre . Commençons par uneplain
fonction.Si nous utilisons un
new
opérateur sur leTree function
, nous l'appelons enconstructor
fonction.Chaque
JavaScript
fonction a unprototype
. Lorsque vous vous connectezTree.prototype
, vous obtenez ...Si vous regardez la
console.log()
sortie ci-dessus , vous pourriez voir une propriété constructeurTree.prototype
et une__proto__
propriété aussi. Le__proto__
représente le surprototype
lequel celafunction
est basé, et comme il s'agit simplement d'un simpleJavaScript function
sansinheritance
configuration, il fait référence auObject prototype
qui 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, .hasOwnProperty
etc ...__proto__
qui a été apporté mon mozilla est obsolète et est remplacé par uneObject.getPrototypeOf
méthode pour obtenir leobject's prototype
.Ajoutons une méthode à notre
Tree
prototype
.Nous avons modifié le
Root
et y avons ajouté unefunction
branche.Cela signifie que lorsque vous créez un
instance
deTree
, vous pouvez appeler sabranch
méthode.Nous pouvons également ajouter
primitives
ouobjects
à notrePrototype
.Ajoutons un
child-tree
à notreTree
.Ici, l'
Child
héritageprototype
de Tree, ce que nous faisons ici est d'utiliser uneObject.create()
méthode pour créer un nouvel objet basé sur ce que vous passez, le voiciTree.prototype
. Dans ce cas, ce que nous faisons est de définir le prototype de Child sur un nouvel objet qui semble identique auTree
prototype. Ensuite, nous définissons leChild's constructor to Child
, sinon, cela indiqueraitTree()
.Child
a maintenant le sienprototype
, ses__proto__
points versTree
et lesTree's prototype
points vers la baseObject
.Maintenant , vous créez un
instance
deChild
et appelbranch
qui est à l' origine disponibleTree
. Nous n'avons pas réellement défini notrebranch
sur leChild prototype
. MAIS, dansRoot prototype
lequel l'enfant hérite.Dans JS, tout n'est pas un objet, tout peut agir comme un objet.
Javascript
a des primitives commestrings, number, booleans, undefined, null.
ils ne le sont pasobject(i.e reference types)
, mais peut certainement agir comme unobject
. Regardons un exemple ici.Dans la première ligne de cette liste, une
primitive
valeur de chaîne est affectée au nom. La deuxième ligne traite le nom comme unobject
et appelle encharAt(0)
utilisant la notation par points.Voici ce qui se passe dans les coulisses: // ce que fait le
JavaScript
moteurIl
String object
n'existe que pour une seule instruction avant d'être détruite (un processus appeléautoboxing
). Revenons à nouveau à notreprototypal
inheritance
.Javascript
prend en charge l'héritage viadelegation
basé surprototypes
.Function
a uneprototype
propriété, qui fait référence à un autre objet.properties/functions
sont regardés deobject
lui - même ou via uneprototype
chaîne s'il n'existe pasUn
prototype
dans JS est un objet queyields
vous au parent d'un autreobject
. [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.https://jsfiddle.net/say0tzpL/1/
Si vous recherchez le violon ci-dessus, le chien a accès à la
toString
méthode, mais elle n'est pas disponible, mais disponible via la chaîne de prototype qui délègue àObject.prototype
Si vous regardez celui ci-dessous, nous essayons d'accéder à la
call
méthode qui est disponible dans chaquefunction
.https://jsfiddle.net/rknffckc/
Si vous recherchez le violon ci-dessus,
Profile
Function a accès à lacall
méthode, mais elle n'est pas disponible dedans, mais disponible via la chaîne de prototype qui délègue àFunction.prototype
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 uneprototype
propriété dont la valeur est videobject
. 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 fonctionconstructor
.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
b1
etb2
, dont le constructeur estBar
et parent est Foo et a deux méthodes à partir de la chaîne de prototypeidentify
etspeak
viaBar
etFoo
https://jsfiddle.net/kbp7jr7n/
Si vous recherchez le code ci-dessus, nous avons un
Foo
constructeur qui a la méthodeidentify()
et unBar
constructeur qui a unespeak
méthode. Nous créons deuxBar
instancesb1
etb2
dont le type parent estFoo
. Maintenant, tout en appelant laspeak
méthode deBar
, nous pouvons identifier qui appelle la parole via laprototype
chaîne.Bar
a maintenant toutes les méthodesFoo
qui sont définies dans sonprototype
. Penchons-nous davantage pour comprendre leObject.prototype
etFunction.prototype
et comment ils sont liés. Si vous recherchez le constructeur deFoo
,Bar
etObject
êtesFunction constructor
.Le
prototype
deBar
estFoo
,prototype
d'Foo
est -Object
et si vous regardez attentivement leprototype
deFoo
est lié àObject.prototype
.Avant de terminer, fermons simplement avec un petit morceau de code ici pour résumer tout ce qui précède . Nous utilisons l'
instanceof
opérateur ici pour vérifier si unobject
a dans saprototype
chaîne laprototype
propriété d'unconstructor
qui résume ci-dessous l'intégralité du grand diagramme.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 !!!!
la source
L'interface avec les classes standard devient extensible. Par exemple, vous utilisez la
Array
classe 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.
la source
Il peut être utile de classer les chaînes prototypes en deux catégories.
Considérez le constructeur:
La valeur de
Object.getPrototypeOf(Person)
est une fonction. En fait, ça l'estFunction.prototype
. Depuis qu'il aPerson
été créé en tant que fonction, il partage le même objet fonction prototype que toutes les fonctions. C'est la même chose quePerson.__proto__
, mais cette propriété ne doit pas être utilisée. Quoi qu'il en soit, avecObject.getPrototypeOf(Person)
vous, montez efficacement l'échelle de ce qu'on appelle la chaîne prototype.La chaîne vers le haut ressemble à ceci:
Person
→Function.prototype
→Object.prototype
(point final)Il est important que cette chaîne prototype ait peu à voir avec les objets qui
Person
peuvent ê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:
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:p
→Person.prototype
→Object.prototype
(point final)Il n'y a pas d'objet fonction dans cette chaîne (bien que cela puisse l'être).
Il
Person
semble donc lié à deux types de chaînes, qui vivent leur propre vie. Pour "sauter" d'une chaîne à l'autre, vous utilisez:.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 ellenew
ne peut être utilisée que sur les fonctions)..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:
Pour résumer:
Il n'est pas surprenant que le nom de la propriété
prototype
puisse prêter à confusion. Il aurait peut-être été plus clair si cette propriété avait été nomméeprototypeOfConstructedInstances
ou quelque chose dans ce sens.Vous pouvez aller et venir entre les deux chaînes prototypes:
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.prototype
est un objet qui a été créé en même temps que la fonction aPerson
été créée. Il aPerson
comme constructeur, même si ce constructeur ne s'est pas encore exécuté. Donc, deux objets sont créés en même temps:Person
elle-mêmeLes 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
: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:
Maintenant, la chaîne prototype de t est un pas plus longue que celle de p :
t
→p
→Person.prototype
→Object.prototype
(point final)L'autre chaîne prototype n'est plus:
Thief
etPerson
les frères et sœurs partagent le même parent dans leur chaîne prototype:Person
}Thief
} →Function.prototype
→Object.prototype
(point final)Le graphique présenté précédemment peut ensuite être étendu à ceci (l'original
Thief.prototype
est omis):Les lignes bleues représentent des chaînes prototypes, les autres lignes colorées représentent d'autres relations:
la source
The Definitive Guide to Object-Oriented JavaScript - une explication vidéo très concise et claire d'environ 30 minutes de la question posée (le sujet sur l'héritage prototypique commence à partir de 5h45 , bien que je préfère écouter la vidéo entière). L'auteur de cette vidéo a également réalisé le site Web du visualiseur d'objets JavaScript http://www.objectplayground.com/ .
la source
J'ai trouvé utile d'expliquer la "chaîne prototype" comme convention récursive lorsqu'elle
obj_n.prop_X
est référencée:s'il
obj_n.prop_X
n'existe pas, vérifiezobj_n+1.prop_X
oùobj_n+1 = obj_n.[[prototype]]
Si le
prop_X
est 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:
http://jsobjects.org
la source
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.
la source
Il y a deux entités distinctes mais liées ici qui doivent être expliquées:
.prototype
propriété des fonctions.[[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:La
.prototype
propriété:Il s'agit d'une propriété qui se trouve uniquement sur les fonctions. En utilisant une fonction très simple:
La
.prototype
propriété contient un objet auquel vous serez affectéb.[[Prototype]]
lorsque vous le ferezvar b = new Bar
. Vous pouvez facilement examiner ceci:L'un des plus importants
.prototype
est celui de laObject
fonction . 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:Maintenant, puisque
.prototype
c'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 surObject.prototype
:Quand vous faites des missions de maquillage à
Function.prototype
tout 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
.la source
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:
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 ferezObject.getPrototypeOf(product)
, vous obtiendrez le modèle d' objet .Les propriétés du produit sont gérées de la manière suivante:
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?
la source
Une autre tentative d'expliquer l' héritage basé sur un prototype JavaScript avec de meilleures images
la source
Considérez l'
keyValueStore
objet suivant :Je peux créer une nouvelle instance de cet objet en procédant comme suit:
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
keyValueStore
objet. Même siget
,set
,delete
,getLength
fera 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
,delete
etgetLength
copie, 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 à
keyValueStore
nouveau l' objet. Je pourrais le réécrire comme ceci:Cela fait exactement la même chose que la version précédente de l'
keyValueStore
objet, 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.la source
Sommaire:
new
mot 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éé.__proto__
propriété fait référence à laprototype
propriété de la fonction constructeur.Exemple:
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:
Par exemple:
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()
la source
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.
la source
un autre schéma montrant __proto__ , les relations prototype et constructeur :
la source
C'est juste que vous avez déjà un objet avec
Object.new
mais vous n'avez toujours pas d'objet lorsque vous utilisez la syntaxe du constructeur.la source
Référence: https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Objects/Object_prototypes
la source
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.
la source