Prototypes et chaîne de prototypes en JavaScript

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 :

  1. Ils peuvent avoir des propriétés étendues librement. ``` var objet = {}; objet.a = 100; var tableau = []; tableau.a = 100; function fonction() {} fonction.a = 100;
  2. Ils possèdent une propriété implicite __proto__. ``` console.log(objet.proto); console.log(tableau.proto); console.log(fonction.proto);
  3. Toute fonction a une propriété explicite prototype. ``` console.log(fonction.prototype);
  4. La propriété __proto__ d'un type de référence pointe vers le prototype de son constructeur. ``` console.log(objet.proto === Object.prototype); // vrai console.log(tableau.proto === Array.prototype); // vrai console.log(fonction.proto === Function.prototype); // vrai
  5. 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 :

  1. Crée un nouvel objet vide.
  2. Définit le __proto__ de cet objet pour qu'il pointe vers le prototype du constructeur.
  3. Exécute la foncsion constructeur avec le conetxte (this) lié au nouvel objet.
  4. 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;
}

Étiquettes: JavaScript Prototypes Chaîne de prototypes Héritage constructeurs

Publié le 24 juin à 05h07