Simplification des prototypes JavaScript dans l’invocation du constructeur
Découvrez les prototypes JavaScript et les chaînes de prototypes, qui expliquent comment les objets sont créés.
En tant que développeur JavaScript, vous avez probablement entendu la phrase : « En JavaScript, chaque objet est créé à partir d’un objet existant. »
Mais comme il existe plusieurs façons (quatre, pour être précis) de créer un objet, par exemple en utilisant un constructeur de fonction ou une classe, cette affirmation peut sembler fausse. Comment créer un objet à partir d’un objet existant ?
Dans cet article, mon objectif est de vous donner une compréhension claire des prototypes JavaScript et de la façon dont les objets sont créés. À la fin, vous serez en mesure de comprendre ces concepts à l’aide d’un diagramme comme celui présenté ci-dessous :
Commençons par la déclaration suivante :
« En JavaScript, chaque objet est lié à un objet existant, et cet objet existant est connu comme le prototype de cet objet. »
Ainsi, autrement dit, chaque objet JavaScript que vous créez est lié à son objet prototype. Cela signifie qu’un nouvel objet JavaScript est toujours lié à son objet prototype.
Considérez cette fonction constructeur :
function Product(name, price) {
this.name = name;
this.price = price;
}
let p1 = new Product('Pen', 1.2);
console.log(Object.getPrototypeOf(p1));
Quand vous créez p1 avec new Product(...)JavaScript fait deux choses importantes pour vous :
- Il crée un nouvel objet
p1. - Il définit le prototype interne de ce nouveau (
p1) objet ([[Prototype]]) àProduct.prototype.
Donc p1 est lié au Product.prototype objet.
Tout autre objet créé à l’aide du nouveau Product(...) sera lié au même Product.prototype objet.
let p2 = new Product('Pencil', 0.8);
console.log(Object.getPrototypeOf(p2));
Puisque les deux p1 et p2 sont créés en utilisant la même fonction constructeur Productils sont liés au même objet prototype et ont accès en lecture aux propriétés de l’objet prototype.
Avant de continuer, regardons les différentes manières de créer un objet en JavaScript :
- Utiliser une fonction comme constructeur
- Utiliser un objet littéral
- Utiliser une classe
- En utilisant le
Object.create()méthode
Modèle d’appel de constructeur
Commençons par la fonction en tant que constructeur. Lorsque vous utilisez une fonction pour créer un objet, elle est également appelée modèle d’appel de constructeur.
En JavaScript, chaque fonction régulière (mais pas les fonctions fléchées) possède un objet prototype. Lorsque vous utilisez une fonction normale comme constructeur, le prototype interne de l’objet nouvellement créé ([[Prototype]]) est lié au prototype de cette fonction. Les fonctions fléchées n’ont pas de propriété prototype, elles ne peuvent donc pas être utilisées comme constructeurs. Pour démontrer cela, imprimez les deux valeurs suivantes :
function Product(title, price) {
this.title = title;
this.price = price;
}
console.log(Product.prototype);
var Invoice = (title, price) => {
this.title = title;
this.price = price;
}
console.log(Invoice.prototype);
Comme le montre le résultat, le prototype d’une fonction fléchée n’est pas défini, elle ne peut donc pas être utilisée comme constructeur pour créer des objets.
Nous ne pouvons donc pas utiliser une fonction flèche comme constructeur pour créer un objet.
Diagramme prototype
Dans cette section, créons un diagramme prototype étape par étape à l’aide du modèle d’appel de constructeur pour créer des objets. Certaines règles que nous allons suivre sont les suivantes :
- Dessiner une fonction sous forme de cercle
- Dessinez l’objet sous forme de rectangle
- Dessinez un objet prototype sous la forme d’un rectangle rouge
Nous avons une fonction Produit :
function Product(title, price) {
this.title = title;
this.price = price;
}
Dessinons le Product fonctionner comme un cercle :
Ensuite, ajoutez une propriété de quantité à la fonction Produit :
Product.prototype.quantity = 10;
Ceci est représenté dans le diagramme en utilisant une réactance rouge et une flèche de Product fonction ci-dessous :
Créons ensuite deux objets, p1 et p2du Product constructeur comme indiqué ci-dessous :
let p1 = new Product('Pen', 100);
let p2 = new Product('Pencil', 200);
Cela peut être représenté dans le diagramme ci-dessous :

Parce que p1 et p2 sont des objets, nous les dessinons sous forme de rectangles. Et depuis le Product constructeur a créé les deux, chaque rectangle a une flèche pointant vers le Product fonction. Si vous vous connectez p1.constructor ou p2.constructorça revient Product.
console.log(p1.constructor === Product);
console.log(p2.constructor === Product);
Jusqu’à présent, nous avons connecté les instances, le constructeur et le prototype.
console.log(p1.quantity);
console.log(p2.quantity);
console.log(p1.hasOwnProperty('quantity'));
console.log(p2.hasOwnProperty('quantity'));
Maintenant, quand vous lisez le quantity propriété sur p1 ou p2JavaScript suit ces étapes :
- Vérifiez l’objet lui-même (
p1) pour son propre propriété nommée quantité. S’il est trouvé, renvoyez cette valeur et arrêtez. - S’il n’est pas trouvé, suivez les instructions internes
[[Prototype]]lien versProduct.prototypeet cherchez la quantité là-bas. Si trouvé sur le prototype, renvoyez cette valeur et arrêtez. - S’il n’est toujours pas trouvé, continuez la chaîne de prototypes jusqu’à
Object.prototypeet vérifiez là-bas. - Si la propriété ne figure nulle part sur la chaîne, renvoyez undefined.
Vous pouvez maintenant suivre la chaîne du prototype pour lire la valeur de la quantité pour p1 et p2. En fait, en regardant le schéma, vous pouvez voir que p1.quantity se résout à la même valeur que p1.constructor.prototype.quantityfourni p1 n’a pas sa propre propriété de quantité.
console.log(p1.quantity == p1.constructor.prototype.quantity);
console.log(p2.quantity == p2.constructor.prototype.quantity);
console.log(p1.quantity)
console.log(p2.quantity)
console.log(p1.constructor.prototype.quantity);
console.log(p2.constructor.prototype.quantity);
Le prototype est accessible de deux manières :
- Grâce au constructeur (
obj.constructor.prototype) - Directement via le serveur interne de l’instance
[[Prototype]]
Lorsque vous créez un objet avec un constructeur, JavaScript définit l’instance [[Prototype]] au prototype de ce constructeur. La plupart des moteurs JavaScript exposent ce lien comme obj.__proto__. Modifions donc le diagramme du prototype pour représenter cela.
Comme vous pouvez le voir, p1.__proto__ fait référence au même objet que p1.constructor.prototypeet le __proto__ de p1 est identique au __proto__ de p2. Par conséquent, JavaScript renvoie true pour les comparaisons ci-dessous.
console.log(p1.quantity == p1.__proto__.quantity);
console.log(p2.quantity == p2.__proto__.quantity);
console.log(p1.constructor.prototype.quantity == p1.__proto__.quantity);
console.log(p2.constructor.prototype.quantity == p2.__proto__.quantity);
console.log(p1.__proto__ == p2.__proto__);
Pour résumer, lorsque vous lisez une propriété d’un objet :
- JavaScript lit la propriété dans l’objet lui-même.
- Si JavaScript trouve la propriété, il lit la valeur.
- Si JavaScript ne trouve pas la propriété, il accède au prototype de l’objet.
- Si JavaScript trouve la propriété, il lit la valeur.
- Si JavaScript ne trouve pas la propriété, il parcourt jusqu’au
Object.prototype. - S’il ne trouve pas de propriété, il la lit comme indéfinie.
Le diagramme du prototype montre également qu’il existe plusieurs chemins pour atteindre le prototype d’un objet. Par exemple, les deux p1.constructor.prototype et p1.__proto__ conduire au même objet prototype de p1.
En rassemblant le tout, nous avons maintenant une fonction constructeur et deux objets créés à partir de celle-ci, comme indiqué ci-dessous :
function Product(title, price) {
this.title = title;
this.price = price;
}
Product.prototype.quantity = 10;
let p1 = new Product('Pen', 100);
let p2 = new Product('Pencil', 200);
Le code ci-dessus peut être traduit en un diagramme prototype comme indiqué ci-dessous.
Vous pouvez maintenant facilement raisonner la question suivante en vous référant au diagramme du prototype :
console.log(p1.constructor === Product);
console.log(p2.constructor === Product);
console.log(p1.quantity);
console.log(p2.quantity);
console.log(p1.hasOwnProperty('quantity'));
console.log(p2.hasOwnProperty('quantity'));
console.log(p1.quantity == p1.constructor.prototype.quantity);
console.log(p2.quantity == p2.constructor.prototype.quantity);
console.log(p1.quantity)
console.log(p2.quantity)
console.log(p1.constructor.prototype.quantity);
console.log(p2.constructor.prototype.quantity);
console.log(p1.quantity == p1.__proto__.quantity);
console.log(p2.quantity == p2.__proto__.quantity);
console.log(p1.constructor.prototype.quantity == p1.__proto__.quantity);
console.log(p2.constructor.prototype.quantity == p2.__proto__.quantity);
console.log(p1.__proto__ == p2.__proto__);
Opération d’écriture
Par défaut, JavaScript vous permet d’ajouter dynamiquement des propriétés à un objet. Par exemple, l’opération suivante fonctionne parfaitement :
var Foo = {};
Foo.koo = 9;
En JavaScript, les opérations d’écriture ciblent toujours l’objet lui-même plutôt que sa chaîne de prototypes. Cela signifie que lorsque vous attribuez une nouvelle propriété, par exemple : p1.color = "red": la propriété est créée comme son propre propriété sur p1.
Autres instances créées à partir du même constructeur, telles que p2n’héritera pas de cette propriété car elle n’existe que sur p1 et non sur le prototype partagé.
let p1 = new Product('Pen', 100);
p1.color = "red";
let p2 = new Product('Pencil', 200);
console.log(p1.color);
console.log(p2.color);
Pour le p2 objet, la valeur de couleur n’est pas définie car aucun objet dans sa chaîne de prototypes ne définit une propriété de couleur.
En JavaScript, si un objet définit une propriété portant le même nom que celle qui existe sur son prototype, la propre propriété de l’objet est prioritaire. Ce comportement est connu sous le nom observation de propriété. Lorsque l’observation de propriété se produit, les recherches sur l’objet renverront la valeur de la propre propriété, masquant ainsi la propriété correspondante sur le prototype sans la modifier.
Product.prototype.quantity = 10;
let p1 = new Product('Pen', 100);
p1.color = "red";
let p2 = new Product('Pencil', 200);
p2.quantity = 56;
console.log(p1.color);
console.log(p2.color);
console.log(p1.quantity);
console.log(p2.quantity);
Maintenant p2 a sa propre propriété de quantité, donc lorsque vous accédez p2.quantityJavaScript le lit directement à partir du p2 objet au lieu du prototype. Le diagramme du prototype mis à jour illustre cela comme indiqué ci-dessous :
Ceci en prototype
Voyons maintenant comment this se comporte dans la chaîne de prototypes. Nous allons modifier le code de base comme indiqué ci-dessous :
function Product(title, price) {
this.title = title;
this.price = price;
}
Product.prototype.quantity = 10;
Product.prototype.log = function(){
console.log(`${this.title} costs ${this.price} and quantity available : ${this.quantity}`);
}
Nous avons ajouté une fonction nommée log au prototype du produit et, à l’intérieur de celui-ci, nous utilisons le this mot-clé pour accéder aux propriétés de l’objet. Le log est ajoutée au prototype, afin que toutes les instances de Product puissent appeler cette méthode pour afficher leurs informations.
let p1 = new Product('Pen', 100);
let p2 = new Product('Pencil', 200);
p1.log();
p2.log();
Quand le log la méthode est appelée p1la valeur de this à l’intérieur de la méthode fait référence au p1 objet. De même, lorsqu’on l’appelle p2, this fait référence au p2 objet.
Si vous souhaitez définir un objet différent comme valeur, vous pouvez utiliser le Modèle d’appel indirect avec des méthodes comme callcomme indiqué ci-dessous.
p1.log.call(p2);
La valeur de this est non déterminé par l’endroit où une fonction est définiemais par comment on l’appelle.
p1.log()→ À l’intérieurlog,thisfait référence à p1.p2.log()→ À l’intérieurlog,thisfait référence à p2.
C’est pourquoi la même méthode sur le prototype fonctionne pour les deux objets :this pointe toujours vers l’objet appelant.
Résumé
- En JavaScript, chaque objet possède un lien interne vers un autre objet appelé son prototype. Ce maillon forme une chaîne, connue sous le nom de chaîne prototypequi est utilisé pour la recherche de propriétés et de méthodes.
- Comme une fonction fléchée n’a pas d’objet prototype, elle ne peut pas être utilisée comme constructeur.
- Si vous attribuez une propriété directement à une instance, elle ombres la propriété du prototype.
- L’opération d’écriture (
=) crée ou met toujours à jour son propres propriétés sur l’objet, pas sur le prototype. - Lorsque vous lisez une propriété, JavaScript recherche la propriété sur l’objet lui-même. S’il n’est pas trouvé, passez au prototype de l’objet et continuez à remonter la chaîne jusqu’à ce que
Object.prototype. Si toujours introuvable, retournezundefined. - À l’aide du modèle d’appel indirect, vous pouvez transmettre explicitement la valeur de cet objet à la méthode créée sur l’objet prototype.
Tous les apprentissages ci-dessus peuvent être résumés dans le diagramme de chaîne prototype suivant.
Source link
