15
Classes ES6+
Programmation Orientée Objet Moderne
Les classes JavaScript sont du sucre syntaxique sur les prototypes, mais apportent une syntaxe claire et des fonctionnalités modernes comme les champs privés (#) et les propriétés statiques.
📘 Syntaxe de Base
class User {
// Champs publics (ES2022)
role = 'user';
// Champ privé (préfixe #)
#password;
constructor(name, password) {
this.name = name; // Propriété publique
this.#password = password; // Propriété privée
}
// Méthode publique
greet() {
return `Hello, ${this.name}!`;
}
// Getter (accès comme propriété)
get displayName() {
return this.name.toUpperCase();
}
// Setter (modification comme propriété)
set displayName(value) {
this.name = value.toLowerCase();
}
// Méthode privée
#validatePassword() {
return this.#password.length >= 8;
}
// Méthode statique (appelée sur la classe, pas l'instance)
static isValidName(name) {
return name.length > 2;
}
}
// Utilisation
const user = new User('Alice', 'secret123');
console.log(user.greet()); // "Hello, Alice!"
console.log(user.displayName); // "ALICE" (getter)
user.displayName = 'Bob'; // Utilise le setter
console.log(user.name); // "bob"
// console.log(user.#password); // ❌ SyntaxError: Private field
console.log(User.isValidName('Al')); // false (static)
🔧 Fonctionnalités des Classes
PUBLIC Champs Publics
class Counter {
count = 0; // Initialisé
increment() {
this.count++;
}
}
Accessibles de partout
PRIVATE Champs Privés
class BankAccount {
#balance = 0;
deposit(amount) {
this.#balance += amount;
}
}
Inaccessibles de l'extérieur
STATIC Méthodes Statiques
class Math2 {
static add(a, b) {
return a + b;
}
}
Math2.add(2, 3); // 5
Appelées sur la classe
🔄 Getters / Setters
class Circle {
#radius = 0;
get area() {
return Math.PI * this.#radius ** 2;
}
}
Propriétés calculées
🧬 Héritage avec extends
Animal (Parent)
↓
Dog (Enfant)
// Classe parente
class Animal {
constructor(name) {
this.name = name;
}
speak() {
return `${this.name} makes a sound`;
}
}
// Classe enfant (hérite de Animal)
class Dog extends Animal {
constructor(name, breed) {
super(name); // ⚠️ Obligatoire : appelle le constructeur parent
this.breed = breed;
}
// Override (surcharge) de la méthode parent
speak() {
return `${this.name} barks!`;
}
// Appeler la méthode parent
speakLikeAnimal() {
return super.speak(); // Appelle Animal.speak()
}
}
const dog = new Dog('Rex', 'Labrador');
console.log(dog.speak()); // "Rex barks!"
console.log(dog.speakLikeAnimal()); // "Rex makes a sound"
console.log(dog instanceof Dog); // true
console.log(dog instanceof Animal); // true
🎮 Constructeur de Classe Interactif
Créez une classe et voyez le code généré.
Cliquez sur "Générer" pour voir le code
🎯 Patterns Avancés
// 1. SINGLETON PATTERN
class Database {
static #instance = null;
constructor() {
if (Database.#instance) {
return Database.#instance;
}
Database.#instance = this;
this.connection = 'Connected';
}
static getInstance() {
if (!Database.#instance) {
Database.#instance = new Database();
}
return Database.#instance;
}
}
const db1 = Database.getInstance();
const db2 = Database.getInstance();
console.log(db1 === db2); // true (même instance)
// 2. FACTORY PATTERN
class User {
constructor(name, role) {
this.name = name;
this.role = role;
}
static createAdmin(name) {
return new User(name, 'admin');
}
static createGuest(name) {
return new User(name, 'guest');
}
}
const admin = User.createAdmin('Alice');
const guest = User.createGuest('Bob');
// 3. BUILDER PATTERN
class QueryBuilder {
#query = '';
select(fields) {
this.#query += `SELECT ${fields} `;
return this; // Chaînage
}
from(table) {
this.#query += `FROM ${table} `;
return this;
}
where(condition) {
this.#query += `WHERE ${condition}`;
return this;
}
build() {
return this.#query.trim();
}
}
const query = new QueryBuilder()
.select('*')
.from('users')
.where('age > 18')
.build();
// "SELECT * FROM users WHERE age > 18"
⚖️ Classes vs Prototypes
// Ancienne méthode (Prototype)
function Person(name) {
this.name = name;
}
Person.prototype.greet = function() {
return 'Hello ' + this.name;
};
const p = new Person('Alice');
// Nouvelle méthode (Class)
class Person {
constructor(name) {
this.name = name;
}
greet() {
return `Hello ${this.name}`;
}
}
const p = new Person('Alice');
💡 Équivalence : Les classes sont du sucre syntaxique. Sous le capot, JavaScript
utilise toujours les prototypes.
Person.prototype existe même avec la syntaxe class.
⚠️ Pièges Courants :
- super() obligatoire : Dans un constructeur enfant,
super()doit être appelé avant d'utiliserthis. - Champs privés vraiment privés :
#fieldn'est pas accessible même viaobj['#field']. C'est une erreur de syntaxe. - this dans les callbacks : Utilisez les arrow functions ou
.bind(this)pour préserver le contexte. - Pas de hoisting : Les classes ne sont pas "hoisted". Déclarez-les avant utilisation.
Best Practice : Utilisez les champs privés (#) pour l'encapsulation. Préférez les
méthodes statiques pour les utilitaires. Utilisez
extends avec parcimonie (composition >
héritage).