Fermer

avril 11, 2022

Comprendre les prototypes et l'héritage prototype—JavaScript


Contrairement aux langages orientés objet qui utilisent un mécanisme d'héritage basé sur les classes, le système d'héritage de JavaScript est prototype. Cet article vous montrera comment réaliser l'héritage en JavaScript grâce au concept d'objets pouvant hériter des propriétés d'autres objets.

Les prototypes ont un impact significatif sur le comportement des objets en JavaScript. Cet article vous aidera à comprendre efficacement le fonctionnement de l'héritage prototypique en JavaScript. Commençons!

La plupart des langages orientés objet comme Java ou PHP utilisent un mécanisme d'héritage basé sur les classes.Il n'y a pas de concept de classes agissant comme un modèle pour créer des objets en JavaScript.

Que signifie l'héritage en JavaScript ?

L'héritage JavaScript est plus largement connu sous le nom d'"héritage prototype". L'héritage prototype utilise le concept dechaînage de prototypes, et il fait référence à la liaison d'objets via la propriété prototype. Lorsqu'une fonction constructeur crée un objet, elle ne le crée pas en fonction du prototype du constructeur ; à la place, il crée un objet lié à l'objet prototype du constructeur.

Cette forme d'héritage via la chaîne de prototypes est communément appelée délégation en JavaScript.

Fonctions constructeur

Toutes les fonctions en JavaScript sont des objets ordinaires, ce qui signifie qu'elles peuvent avoir des propriétés. Ils mettent en œuvre le[[Call]]mais lorsqu'ils sont invoqués avec l'opérateur new, ils deviennent des constructeurs (usines de fabrication d'objets).

une fonction Personne() {} 

laisseriféoma= Nouveau Personne() 

JavaScript a plusieurs objets intégrés (objet, fonction, tableau, chaîne, etc.), et chaque fonction de JavaScript est une instance de l'objet intégréune fonctionobjet.


une fonction Personne() {}


laisserPersonne= Nouveau Une fonction()

Les fonctions en JavaScript qui peuvent être utilisées comme constructeurs, qu'elles soient intégrées ou définies par l'utilisateur, ont par défaut une propriété "prototype". Cette propriété de prototype n'est disponible que sur les fonctions, pas sur les objets.

Un constructeur (fonction Peron(){}) envoie un lien prototype à son objet prototype (objet Person.prototype), qui renvoie un lien constructeur.

Lorsqu'une fonction est créée ou déclarée, un autre objet ordinaire (l'objet prototype de la fonction) est créé en interne et défini comme valeur initiale de la propriété prototype de la fonction.



une fonction Personne() {}Personne.prototype= {} 

Cet objet prototype est utilisé pour activer l'héritage basé sur le prototype et les propriétés partagées. Chaque objet créé par un constructeur a un lien implicite ou une référence pointant vers la valeur de l'objet prototype de son constructeur. Je vais expliquer cet objet prototype plus en détail un peu plus tard.

L'intégréObjet La fonction est l'un des objets fondamentaux de JavaScript. Il a une propriété prototype dessus qui pointe vers son objet prototype—Objet.prototype.Objet.prototypeest un objet JavaScript prototype et il se trouve au sommet de la chaîne de prototypes, donc son[[Prototype]]l'emplacement interne est nul.

Objet.prototypecontient un tas de méthodes internes qui sont disponibles pour tous les objets (comme.toString()etvaleur de() ). Tous les objets intégrés (chaîne, fonction, etc.) dans JavaScript descendent duObjet.prototypeobjet, et la chaîne de prototypes de chaque objet renvoie finalement àObjet.prototype.

Liaison de prototype JavaScript" title="Liaison de prototype JavaScript"/></p>
<p>Certains objets ne sont pas directement liés à<code>Objet.prototype</code> comme prototype ;  à la place, ils ont un autre objet avec un ensemble différent de propriétés par défaut.</p>
<p>Les fonctions obtiennent leurs propriétés par défaut à partir de<code>Fonction.prototype</code>et les tableaux obtiennent le leur de<code>Array.prototype</code> .  Tous les deux<code>Fonction.prototype</code>et<code>Array.prototype</code>lien direct vers<code>Objet.prototype</code>.</p>
<pre class= une fonction Personne(Nom,travail,passe-temps){ cette.Nom=Nom; cette.travail=travail; cette.passe-temps=passe-temps; } laisseriféoma= Nouveau Personne("Iféoma", "Développeur de logiciels", "Dansant");iféoma->Personne.prototype → Objet.prototype →nul laisserarr= [1, "Ify", 3, vrai];arr->Déployer.prototype->Objet.prototype-> nul

[[Prototype]] vs .prototype vs objet prototype

Tous les objets en JavaScript ont un emplacement interne appelé[[Prototype]] , qui est une référence ou un lien vers un autre objet. La valeur pointée par l'emplacement interne du prototype d'un objet est généralement appelée "le prototype de cet objet".

Il y a une différence entre le propre d'un objet[[Prototype]] , une propriété prototype sur une fonction constructeur et un objet prototype. C'est un choix de dénomination très déroutant, mais je vais le décomposer avec l'exemple ci-dessous.


une fonction Personne(Nom){
  cette.Nom=Nom;
}

laisseriféoma= Nouveau Personne("Iféoma")console.Journal(Objet.getPrototypeOf(iféoma) ===Personne.prototype);console.Journal(iféoma.__proto__===Personne.prototype);m

console.Journal(Objet.getPrototypeOf(Personne) ===Une fonction.prototype);console.Journal(Personne.__proto__===Une fonction.prototype);m
  • Personne est une fonction, donc par défaut, c'est une instance de l'objet fonction intégré. La valeur de sa propre[[Prototype]]est l'intégréFonction.prototypeobjet.

  • Personnepossède également un objet prototype appeléPersonne.prototype—l'objet créé lorsque la fonctionPersonne a été déclaré. Cet objet prototype sera le prototype de toutes les instances créées via lePersonneplan lors de l'utilisation duNouveaumot-clé—commeiféomacomme vu ci-dessus.

  • iféomaest un exemple dePersonne,donc son propre[[Prototype]]seront directement liés àPersonne.prototype.

  • Les fonctions en JavaScript qui peuvent être utilisées comme constructeurs ont une propriété prototype par défaut qui pointe vers son objet prototype. LePersonnela propriété prototype pointe vers son objet prototype—Personne.prototype.

Leprotopropriété est une propriété accesseur sur Object.prototype avec un getter (qui expose la valeur de l'interne d'un objet[[Prototype]]) et setter (permet à un objet[[Prototype]] à modifier) ​​fonction. Bien qu'il soit implémenté dans la plupart des navigateurs modernes, leproto La propriété est obsolète et n'est pas standard pour accéder à la chaîne de prototypes. Les normes actuelles fournissent un équivalentObjet.getPrototypeOf()méthode utilisée pour suivre la chaîne du prototype ou récupérer le[[Prototype]]d'un objet depuis ECMAScript 2015.

Chaînage de prototypes

laisseriféoma= {Nom: "Iféoma",travail: "Développeur de logiciels",passe-temps: "Dansant"
}

Dans l'extrait ci-dessus, nous avons créé un objet simple avec la syntaxe littérale. Que se passe-t-il si nous voulons créer plus d'objets avec différents noms, emplois, etc. ? Il existe de nombreuses façons d'y parvenir en JavaScript, mais nous utiliserons une fonction constructeur.



une fonction Personne(Nom,travail,passe-temps){
  cette.Nom=Nom;
  cette.travail=travail;
  cette.passe-temps=passe-temps;
}


laisseriféoma= Nouveau Personne("Iféoma", "Développeur de logiciels", "Dansant");

On peut créer autant d'instances qu'on veut à partir duPersonneconstructeur en ajoutantNouveauà l'appel.

Voyons comment leNouveaul'opérateur fonctionne.

  • Quand on met leNouveauopérateur devant un appel de fonction, la première chose qui se passe est qu'un tout nouvel objet vide est créé.

  • Ensuite, il invoque la fonction devant laquelle il a été appelé avec les arguments spécifiés. L'appel d'une fonction crée un nouveau contexte d'exécution avec uncette mot-clé qui lui est défini. La valeur decetteici pointera vers le tout nouvel objet vide créé au départ.

  • Ensuite, il ajoute les propriétés que nous avons définies à l'objet vide (nom, travail, passe-temps).

  • Si la fonction ne renvoie pas d'objet, elle suppose qu'elle est censée renvoyer lecettemot-clé, et, enfin, il affecte l'objet à la variable (ifeoma).

Par exemple, disons que nous avons des méthodes dont nous voulons que nos instances héritent ou auxquelles elles aient accès. Nous devons ajouter les méthodes à laPersonne propriété du prototype. La propriété prototype d'un constructeur est l'endroit où nous définissons les méthodes et les propriétés que nous voulons partager entre toutes les instances.

Personne.prototype.obtenirNom = une fonction() {
  retourner cette.Nom;
};iféoma.obtenirNom(); 

Puisque nous voulons leobtenirNomque la méthode soit la même pour chaque instance, nous économisons de la mémoire en la conservant dans la propriété prototype de notre fonction constructeur, créant ainsi une relation de délégation ici pour chaque instance créée parPersonneauPersonne.prototype objet. De cette façon, il ne doit être en mémoire qu'une seule fois, plutôt que pour chaque instance. Cela vous éviterait d'avoir à dupliquer du code, améliorerait les performances et nécessiterait moins de mémoire.

Chaque instance dePersonneaura accès à ceobtenirNom méthode. Par la suite, les propriétés ou méthodes ajoutées auPersonneLa propriété prototype est accessible à tous les objets partageant le prototype.

Lorsque nous essayons d'accéder aux méthodes ou aux propriétés d'un objet, la fonction intégrée par défaut de JavaScript[[GetPrototypeOf]]méthode interne effectue les opérations suivantes :

  • Il vérifie si le nom de la propriété est disponible à l'intérieur de l'objet lui-même via le[[prototype]] fente interne. S'il le trouve, la valeur sera renvoyée.

  • S'il ne trouve pas directement la propriété demandée sur l'objet, l'opération remontera la chaîne de prototypes. Le prototype de l'objet sera recherché, qui est la propriété prototype de son parent.

  • Chaque maillon de la chaîne de prototypes est parcouru, un maillon à la fois, jusqu'à ce qu'il trouve un nom de propriété correspondant. Le[[Prototype]]la chaîne est terminée lorsqu'elle atteint leObjet.prototypeobjet, qui a null comme prototype et sert de maillon final dans cette chaîne de prototypes.

  • Undefined sera renvoyé par l'opération si aucune propriété correspondante n'est trouvée.

Selon la spécification JavaScript, la chaîne de prototypes d'un objet doit avoir une longueur finie (c'est-à-dire, à partir de n'importe quel objet, en appliquant de manière récursive le[[GetPrototypeOf]]méthode interne à son résultat devrait finalement conduire à la valeurnul).

C'est ainsi que fonctionne la chaîne de prototypes, et c'est ce qui rend possible l'héritage. Il convient également de noter que si vous avez un objet qui définit une méthode ou une propriété du même nom que son parent, le[[GetPrototypeOf]]retournera la propriété de l'objet.

Syntaxe de classe

Leclasse a été ajouté dans la spécification ES6 publiée en 2015. Il est considéré comme un sucre syntaxique superposé à l'héritage basé sur le prototype actuel. Outre de simples changements syntaxiques, certaines choses fonctionnent différemment dans leur comportement, mais nous ne couvrirons pas ces différences dans cet article.

Réécrivons notrePersonnefonction à l'aide de laclassesyntaxe.


classe Personne{



  constructeur(Nom,travail,passe-temps){
    cette.Nom=Nom;
    cette.travail=travail;
    cette.passe-temps=passe-temps;
  }
  
  obtenirNom(){
    retourner cette.Nom}
}


laisseriféoma= Nouveau Personne("Iféoma", "Développeur de logiciels", "Dansant")

Que se passe-t-il lorsque vous utilisez leclassela syntaxe n'est pas différente de la définition d'une fonction constructeur qui suit le système d'héritage basé sur un prototype, mais en utilisantclasserend votre code beaucoup plus facile à lire.

Résumé

Résumons:

  • Tous les objets en JavaScript ont un caché[[Prototype]]propriété qui est soit un autre objet, soit null.

  • Le système d'héritage de JavaScript, comme nous l'avons vu, est prototypique car les objets peuvent hériter des propriétés d'autres objets.

  • L'ajout de méthodes ou de propriétés au prototype du constructeur le rend disponible en mémoire une seule fois et non pour chaque instance.

  • Lorsqu'un constructeur est appelé avec le mot clé new, il crée un nouvel objet et son prototype est défini comme le prototype de l'objet résultant.




Source link