Aller au contenu principal

Module JS.7 – Programmation Orientée Objet

Objectif

Maîtriser la POO en JavaScript : prototypes, classes ES6, héritage, et toutes les fonctionnalités orientées objet pour créer des architectures modulaires.

Théorie

Prototypes (Méthode classique)

JavaScript utilise un système de prototypes plutôt qu'un modèle de classes traditionnel.

Fonctions constructrices

function Personne(nom, age) {
this.nom = nom;
this.age = age;
}

const jean = new Personne("Jean", 30);
console.log(jean.nom); // "Jean"

Le mot-clé new :

  1. Crée un nouvel objet vide
  2. Lie this à cet objet
  3. Exécute la fonction constructrice
  4. Retourne l'objet (sauf si la fonction retourne autre chose)

Prototype

Chaque fonction a une propriété prototype partagée par toutes les instances.

Personne.prototype.saluer = function() {
return `Bonjour, je suis ${this.nom}`;
};

jean.saluer(); // "Bonjour, je suis Jean"

Chaîne de prototypes :

// jean -> Personne.prototype -> Object.prototype -> null

jean.hasOwnProperty('nom'); // true (méthode d'Object.prototype)

Héritage avec prototypes

function Etudiant(nom, age, ecole) {
Personne.call(this, nom, age); // Appelle le constructeur parent
this.ecole = ecole;
}

// Hérite du prototype
Etudiant.prototype = Object.create(Personne.prototype);
Etudiant.prototype.constructor = Etudiant;

Etudiant.prototype.etudier = function() {
return `${this.nom} étudie à ${this.ecole}`;
};

const etudiant = new Etudiant("Marie", 20, "ESIEA");
etudiant.saluer(); // Hérite de Personne
etudiant.etudier(); // Méthode propre

Classes ES6

Syntaxe moderne introduite en ES6, plus claire que les prototypes.

Déclaration de classe

class Personne {
constructor(nom, age) {
this.nom = nom;
this.age = age;
}

saluer() {
return `Bonjour, je suis ${this.nom}`;
}
}

const jean = new Personne("Jean", 30);
jean.saluer(); // "Bonjour, je suis Jean"

Sous le capot : Les classes ES6 sont du sucre syntaxique sur les prototypes.

Propriétés et méthodes

class Personne {
// Propriété d'instance
constructor(nom, age) {
this.nom = nom;
this.age = age;
}

// Méthode d'instance
saluer() {
return `Bonjour, je suis ${this.nom}`;
}

// Méthode statique
static comparer(a, b) {
return a.age - b.age;
}

// Getter
get description() {
return `${this.nom} a ${this.age} ans`;
}

// Setter
set nouvelAge(age) {
if (age > 0) {
this.age = age;
}
}
}

// Utilisation
const p1 = new Personne("Jean", 30);
const p2 = new Personne("Marie", 25);
Personne.comparer(p1, p2); // Méthode statique
p1.description; // Getter
p1.nouvelAge = 31; // Setter

Champs de classe (ES2022)

class Personne {
nom; // Champ public
#age; // Champ privé (ES2022)

constructor(nom, age) {
this.nom = nom;
this.#age = age;
}

getAge() {
return this.#age; // Accessible dans la classe
}
}

const p = new Personne("Jean", 30);
p.nom; // "Jean" (public)
p.#age; // Erreur (privé)
p.getAge(); // 30 (via méthode)

Héritage

class Etudiant extends Personne {
constructor(nom, age, ecole) {
super(nom, age); // Appelle le constructeur parent
this.ecole = ecole;
}

etudier() {
return `${this.nom} étudie à ${this.ecole}`;
}

// Override
saluer() {
return super.saluer() + ` et je suis étudiant`;
}
}

const etudiant = new Etudiant("Marie", 20, "ESIEA");
etudiant.saluer(); // "Bonjour, je suis Marie et je suis étudiant"
etudiant.etudier(); // "Marie étudie à ESIEA"

super :

  • super() : Appelle le constructeur parent
  • super.methode() : Appelle une méthode du parent

Méthodes privées (ES2022)

class Personne {
#calculerAge() {
// Méthode privée
return this.age;
}

afficherAge() {
return this.#calculerAge(); // Accessible dans la classe
}
}

Mixins

JavaScript ne supporte pas l'héritage multiple, mais on peut utiliser des mixins.

const Loggable = {
log(message) {
console.log(`[${this.constructor.name}] ${message}`);
}
};

const Sauvegardable = {
sauvegarder() {
// Logique de sauvegarde
return true;
}
};

class Personne {
constructor(nom) {
this.nom = nom;
}
}

// Appliquer les mixins
Object.assign(Personne.prototype, Loggable, Sauvegardable);

const p = new Personne("Jean");
p.log("Créé"); // [Personne] Créé
p.sauvegarder(); // true

Composition vs Héritage

Héritage : "Est un" (Etudiant est une Personne) Composition : "A un" (Personne a une Adresse)

// Composition
class Adresse {
constructor(rue, ville) {
this.rue = rue;
this.ville = ville;
}
}

class Personne {
constructor(nom, adresse) {
this.nom = nom;
this.adresse = adresse; // Composition
}
}

const adresse = new Adresse("123 Rue", "Paris");
const personne = new Personne("Jean", adresse);

this et binding

Le contexte this peut être problématique en JavaScript.

Problème :

class Personne {
constructor(nom) {
this.nom = nom;
}

saluer() {
console.log(`Bonjour ${this.nom}`);
}
}

const p = new Personne("Jean");
p.saluer(); // "Bonjour Jean"

const saluer = p.saluer;
saluer(); // Erreur : this est undefined

Solutions :

  1. Arrow functions (recommandé)
class Personne {
constructor(nom) {
this.nom = nom;
}

saluer = () => {
console.log(`Bonjour ${this.nom}`); // this toujours lié
}
}
  1. bind
const saluer = p.saluer.bind(p);
saluer(); // "Bonjour Jean"
  1. call/apply
p.saluer.call(p);  // Appelle avec this = p

Exercice

  1. Prototypes

    • Créez une fonction constructrice
    • Ajoutez des méthodes au prototype
    • Testez l'héritage avec prototypes
  2. Classes ES6

    • Créez une classe avec constructeur
    • Ajoutez des méthodes, getters, setters
    • Créez une classe enfant avec héritage
  3. Champs privés

    • Utilisez les champs privés (#)
    • Testez l'encapsulation
    • Créez des méthodes privées
  4. Mixins

    • Créez des mixins réutilisables
    • Appliquez-les à des classes
    • Testez la composition
  5. this et binding

    • Testez les problèmes de this
    • Utilisez arrow functions
    • Testez bind, call, apply

Quiz

  1. Que fait new en JavaScript ?

    • Crée une nouvelle variable
    • Crée un nouvel objet et lie this
    • Importe un module
  2. Quelle est la différence entre class et function constructrice ?

    • Aucune différence
    • class est du sucre syntaxique sur prototypes
    • class est plus rapide
  3. Comment appeler le constructeur parent ?

    • parent()
    • super()
    • this.parent()
  4. Que signifie # devant une propriété ?

    • Public
    • Privé (ES2022)
    • Statique
  5. Que fait Object.assign() avec prototypes ?

    • Copie un objet
    • Applique des mixins
    • Crée un héritage

Mini défi

Mission : Créer un système POO complet

Créez un système de gestion de bibliothèque avec POO :

Structure :

  1. Classe abstraite Empruntable

    • Méthodes abstraites : emprunter(), retourner(), estDisponible()
    • Propriétés communes : titre, auteur
  2. Classe Livre

    • Hérite de Empruntable (ou implémente interface)
    • Propriétés : isbn, pages
    • Implémente toutes les méthodes
  3. Classe DVD

    • Hérite de Empruntable
    • Propriétés : duree, realisateur
    • Implémente toutes les méthodes
  4. Mixin Loggable

    • Méthode log(message) pour enregistrer les actions
    • Réutilisable sur plusieurs classes
  5. Classe Bibliotheque

    • Collection de Livres/DVDs (composition)
    • Méthodes : ajouter(), rechercher(), emprunter(), retourner()
    • Utilise le mixin Loggable

Critères :

  • ✅ Utilisation de classes ES6
  • ✅ Héritage approprié
  • ✅ Champs privés si nécessaire
  • ✅ Mixins pour réutilisabilité
  • ✅ Composition où approprié
  • ✅ Code bien structuré et documenté

Objectif : Maîtriser la POO complète en JavaScript et créer une architecture propre et modulaire.


Validation : Vous pouvez passer au module suivant quand vous maîtrisez prototypes, classes, héritage et mixins.