En JavaScript, la notion de prototype et de chaîne de prototypes est fondamentale pour la programmation orientée objet. Les prototypes permettent le partage de propriétés et de méthodes entre objets, tandis que la chaîne de prototypes définit l'ordre de recherche lors de l'accès aux propriétés.
Création d'objets
Il existe plusieurs façons de créer des objets en JavaScript :
- Notation littérale :
var premier = {nom: 'premier'}; - Constructeur Object :
var deuxieme = new Object({nom: 'deuxieme'}); - Fonction constructeur : ```
var Constructeur = function(nom) { this.nom = nom; };
var troisieme = new Constructeur('troisieme');
- Object.create : ```
var base = {nom: 'base'};
var quatrieme = Object.create(base);
Fonctions constructeurs
Une fonction constructeur définit un modèle pour créer des objets. Par exemple :
function Personne(nom, age) {
this.nom = nom;
this.age = age;
this.categorie = 'adulte';
}
Les raccourcis de syntaxe comme var a = {}; sont équivalents à var a = new Object();, et var b = []; à var b = new Array();.
Règles des prototypes
Les types de référence (tableaux, objets, fonctions) partagent des caractéristiques communes :
- Ils peuvent avoir des propriétés étendues librement. ```
var objet = {}; objet.a = 100;
var tableau = []; tableau.a = 100;
function fonction() {} fonction.a = 100;
- Ils possèdent une propriété implicite
__proto__. ``` console.log(objet.proto); console.log(tableau.proto); console.log(fonction.proto); - Toute fonction a une propriété explicite
prototype. ``` console.log(fonction.prototype); - La propriété
__proto__d'un type de référence pointe vers leprototypede son constructeur. ``` console.log(objet.proto === Object.prototype); // vrai console.log(tableau.proto === Array.prototype); // vrai console.log(fonction.proto === Function.prototype); // vrai - Lors de l'accès à une propriété, si elle n'existe pas sur l'objet, la recherche continue dans
__proto__(le prototype du constructeur). ``` function Utilisateur(nom) { this.nom = nom; } Utilisateur.prototype.saluer = function() { alert(this.nom); }; var user = new Utilisateur('Alice'); user.afficherNom = function() { console.log(this.nom); }; user.afficherNom(); // Alice user.saluer(); // Alice, car la méthode est trouvée via le prototype
Chaîne de prototypes
La chaîne de prototypes est une séquence de prototypes liés par __proto__, se terminant à Object.prototype (dont __proto__ est null). Exemple :
function Voiture(marque) {
this.marque = marque;
}
Voiture.prototype.demarrer = function() {
console.log('Démarrage...');
};
var auto = new Voiture('Toyota');
auto.demarrer(); // Trouvé dans Voiture.prototype
auto.toString(); // Trouvé dans Object.prototype via la chaîne
Si une propriété n'est pas trouvée, la recherche remonte la chaîne jusqu'à Object.prototype.
Relations entre prototype, instance et constructeur
Prenons un exemple :
var Personne = function(prenom) { this.prenom = prenom; };
var instance = new Personne('Bob');
console.log(Personne.prototype === instance.__proto__); // vrai
console.log(Personne.prototype.constructor === Personne); // vrai
L'instance est créée via new sur le constructeur. Le prototype du constructeur et le __proto__ de l'instance pointent vers le même objet. Le constructor du prototype pointe vers le constructeur.
Exemple d'héritage par chaîne de prototypes
Pour implémenter un style jQuery-like :
function Selecteur(id) {
this.element = document.getElementById(id);
}
Selecteur.prototype.contenu = function(valeur) {
if (valeur) {
this.element.innerHTML = valeur;
return this; // Pour les appels en chaîne
} else {
return this.element.innerHTML;
}
};
Selecteur.prototype.ecouter = function(type, rappel) {
this.element.addEventListener(type, rappel, false);
return this;
};
Utilisation :
var div = new Selecteur('maDiv');
div.ecouter('clic', function() { alert('Cliqué !'); });
div.contenu('Cliquez ici');
console.log(div.contenu());
Détection de types avec instanceof et constructor
instanceof vérifie si un objet est une instance d'un constructeur en parcourant la chaîne de prototypes :
var Chien = function(nom) { this.nom = nom; };
var animal = new Chien('Rex');
console.log(animal instanceof Chien); // vrai
console.log(animal instanceof Object); // vrai, car Object est dans la chaîne
constructor identifie le constructeur direct d'une instance :
console.log(animal.__proto__.constructor === Chien); // vrai
console.log(animal.__proto__.constructor === Object); // faux
Pour vérifier si une variable est un tableau, on peut utiliser instanceof :
var liste = [];
console.log(liste instanceof Array); // vrai
console.log(typeof liste); // object, moins précis
Fonctionnement de l'opérateur new
Lors de l'exécution de new Constructeur(arguments), JavaScript effectue les étapes suivantes :
- Crée un nouvel objet vide.
- Définit le
__proto__de cet objet pour qu'il pointe vers leprototypedu constructeur. - Exécute la foncsion constructeur avec le conetxte (
this) lié au nouvel objet. - Retuorne l'objet si la constructeur ne retourne pas d'objet explicite, sinon retourne l'objet explicite.
Pseudo-code illustratif :
function simulerNew(Constructeur, ...args) {
var objet = {};
objet.__proto__ = Constructeur.prototype;
var resultat = Constructeur.apply(objet, args);
return (typeof resultat === 'object' && resultat !== null) ? resultat : objet;
}