Informatique


Les prototypes

Aller à

JS est orienté prototype

Le JS, contrairement aux autres langages de programmation, utilise pour construire les objets des prototypes.
Le prototype fournit des fonctions et des propriétés aux objets en plus des propriétés et méthodes déjà présents au niveau de l'objet lui-même.

Le grand avantage de cette organisation est que la modification du prototype profite à tous les objets créés avant cette modification!
Donc, si on ajoute une propriété ou une méthode au prototype d'un objet, cette propriété ou cette méthode sera utilisable par tous les objets construits sur ce prototype.


Le label [[Prototype]]

Démo
<h2>Créer un prototype vide avec une fonction constructeur</h2>
<script>
function Pvide(){
	
}
pv1=new Pvide();
console.log(pv1);
</script>

On constate:
au niveau de l'objet pv1: on a 1 propriété: [[Prototype]] , cette dernière à pour valeur Object. Cela veut dire que l'objet de prototype Pvide hérite du prototype Object.

Si on développe cette propriété on remarque que celle-ci contient le constructeur Pvide (c'est normal puisque Pvide construit des objets) et une propriété [[Prototype]] évaluée à Object.

Si on développe cette propriété on remarque que celle-ci contient la méthode constructeur Object() et une série d'autres méthodes qui ont été ajoutées au prototype Object.

Le prototype dont la méthode constructeur est Object() est le dernier de la hiérarchie, en effet, ce prototype n'a pas de [[Prototype]]. .


Les prototypes sont des fonctions

Rendez-vous sur la console...

Démo
<h2>Les prototypes sont des fonctions</h2>
<script>
class Pvide(){
	
}

</script>

Si on tape Pvide dans la console, celle-ci renvoie le f de fonction.
Idem pour Object, String, Number, etc.

C'est logique quand on sait que le constructeur d'objet prend toujours le nom de la classe où il est défini.


Un autre exemple

Reprenons le constructeur Animal déjà utilisé précédemment:

Démo
<h2<Créons des objets de type Animal</h2<
<script>
// Constructeur Animal
function Animal(nom,sexe,age) {
// Initialisation des propriétés de l'objet
	this.nom=nom;
	this.sexe=sexe;
	this.age=age;		
	this.photo=this.nom+".jpg";
	
	this.affic=function(){
		var s= (this.sex==="F")? "Femelle":"Mâle";
		return "<div>"+s+" - "+this.nom+" - "+this.age+" ans"+" - "+this.photo+"</div>";
	}	
}
// Instanciation d'un objet à partir du constructeur
var monPinguin = new Animal("Costard","M","5");
console.log(monPinguin);
document.write(monPinguin.affic());
</script>

On constate:
au niveau de l'objet monPinguin: on a 1 méthode affic() et 5 propriétés: age, nom, photo, sexe, [[Prototype]] , cette dernière à pour valeur Object.

Si on développe cette propriété on remarque que celle-ci contient la méthode constructeur Animal (c'est normal puisque tous les objets Animal sont construit selon cette méthode) et une propriété [[Prototype]] qui représente le prototype sur lequel est construit le prototype Animal.

Si on développe cette propriété on remarque que celle-ci contient la méthode constructeur Object (c'est normal puisque tous les objets sont construit selon cette méthode) et une série d'autres méthodes qui ont été ajoutées au prototype.

Et on développe pour arriver au bout de la chaîne.

La propriété __proto__ permet de renvoyer le prototype d'un objet.
Tous les objets trouvent cette propriété au sommet de la hiérarchie d'héritage, c'est assez normal au demeurant!


L'héritage des prototypes

Exemple: un objet qui utilise une méthode héritée du prototype Object

Démo
<h2<Créons des objets de type Animal</h2<
<script>
// Constructeur Animal
function Animal(nom,sexe,age) {
// Initialisation des propriétés de l'objet
	this.nom=nom;
	this.sexe=sexe;
	this.age=age;		
	this.photo=this.nom+".jpg";
	
	this.affic=function(){
		var s= (this.sex==="F")? "Femelle":"Mâle";
		return "<div>"+s+" - "+this.nom+" - "+this.age+" ans"+" - "+this.photo+"</div>";
	}	
}
// Instanciation d'un objet à partir du constructeur
var monPinguin = new Animal("Costard","M","5");
console.log(monPinguin.valueOf());
</script>

On constate:

  • Le navigateur tente de déterminer si l'objet monPinguin implémente une méthode valueOf()
  • Aucune n'est présente, le navigateur vérifie donc si le prototype objet de monPinguin (Animal) contient cette méthode
  • Pas de valueOf() non plus, donc le navigateur regarde si le prototype objet du constructeur Animal() possède cette méthode. Il y en a une, donc il l'appelle et tout va bien !


Ajouter une méthode au prototype (PM)

On ne peut pas ajouter des propriétés et des méthodes "à la volée" comme pour les objets littéraux.
Si on veut ajouter des propriétés et/ou des méthodes à une classe il est obligatoire d'utiliser la propriété prototype de l'objet (une classe est un objet en JS!).

On peut ajouter des méthodes au sein du prototype de l'objet, pour ce faire on utilise la propriété prototype du type Animal.

Démo
<h2<Créons des objets de type Animal</h2<
<script>
// Constructeur Animal
function Animal(nom,sexe,age) {
// Initialisation des propriétés de l'objet
	this.nom=nom;
	this.sexe=sexe;
	this.age=age;		
	this.photo=this.nom+".jpg";
	
	this.affic=function(){
		var s= (this.sex==="F")? "Femelle":"Mâle";
		return "<div>"+s+" - "+this.nom+" - "+this.age+" ans"+" - "+this.photo+"</div>";
	}	
}
// Instanciation d'un objet à partir du constructeur
var monPinguin = new Animal("Costard","M","5");
Animal.prototype.afficNomMaj=function(){
	document.write(this.nom.toUpperCase());
}
monPinguin.afficNomMaj();
console.log(monPinguin);
</script>

On constate dans la console que la méthode afficNomMaj a bien été rajoutée au prototype de l'objet monPinguin, dorénavant tous les objets de type Animal auront accès à cette méthode.


La chaîne des prototypes (PM)

Voici un script qui renvoie la chaîne de prototypes héritée par un objet.

Démo
<head>
 <meta charset="utf-8">
<script src="ofonc_6.js"></script>
</head>
<body>
<h2>Créer un prototype vide</h2>
<script>
function herit(monobj){
	var proto=Object.getPrototypeOf(monobj);
	
	var heritage=[];
	
	while(proto !== null){
		
		heritage[heritage.length]=proto.constructor.name;
		
		proto=Object.getPrototypeOf(proto);
	}
	return heritage;
}
var monPinguin = new Animal("Costard","M","5");
var stich = new Chien("Stich","M","6");
document.write(stich.affic());
console.log(herit(monPinguin));
console.log(herit(stich));
console.log(herit(document));
var div=document.getElementsByTagName("div")[0];
console.log(herit(div));
</script>
</body>

L'image en prime...

On constate:

  • getPrototypeOf() est une méthode implémentée dans le prototype Object
  • constructor est une propriété de chaque type d'objet
  • name est une propriété de la propriété constructor