Les prototypes en JavaScript
Le prototype est un mécanisme qui permet à un objet d’hériter des propriétés et méthodes d’un autre objet. Contrairement à d’autres langages orientés objet qui utilisent des classes pour définir cet héritage, JavaScript s’appuie sur les prototypes.
Qu’est-ce qu’un prototype ?
Lorsqu’on crée un objet en JavaScript, cet objet hérite automatiquement d’un ensemble de propriétés et de méthodes provenant de son prototype. Ce prototype est un autre objet lié au premier via la chaîne des prototypes. Cela permet de réutiliser des méthodes sans les dupliquer dans chaque objet.
Exemple :
const user = { firstName: 'John', lastName: 'Doe' };
Même si l’objet user ne déclare explicitement que deux propriétés firstName
et lastName
, il a accès à des méthodes comme toString()
ou hasOwnProperty()
. Cela est dû au fait que user
hérite du prototype natif d’un objet JavaScript appelé Object.prototype
Comment fonctionne l’accès aux propriétés ?
Lorsque vous essayez d’accéder à une propriété ou méthode sur un objet, JavaScript va d’abord chercher cette propriété dans l’objet lui-même. Si elle n’existe pas, il remonte dans la chaîne des prototypes jusqu’à la trouver, ou retourne undefined
si elle n’existe nulle part.
Visualiser le prototype d’un objet
Pour examiner le prototype d’un objet, vous pouvez utiliser la méthode Object.getPrototypeOf()
:
Le prototype d’un objet dépend de son type. Par exemple, le prototype des chaînes de caractères est String.prototype
, celui des tableaux est Array.prototype
, et ainsi de suite.
Exemple avec une chaîne de caractères :
console.log(Object.getPrototypeOf("John")); // Affiche String.prototype
Ici, vous avez accès aux méthodes spécifiques aux chaînes de caractères, comme charAt()
, toUpperCase()
, etc. À leur tour, ces prototypes spécialisés comme String.prototype, Array.prototype ou Date.prototype héritent également de Object.prototype.
Créer un prototype avec des classes
Bien que les prototypes soient la base de l’héritage en JavaScript, les classes introduites avec ECMAScript 6 offrent une syntaxe plus familière aux développeurs venant d’autres langages orientés objet.
Exemple de classe :
class User {
constructor(firstName, lastName) {
this.firstName = firstName;
this.lastName = lastName;
}
fullName() {
return this.firstName + ' ' + this.lastName;
}
}
const user = new User('John', 'Doe');
console.log(user.fullName()); // Affiche 'John Doe'
Dans cet exemple, User
est une classe qui, lorsqu’elle est instanciée avec new User()
, crée un objet avec un prototype contenant les méthodes définies dans la classe, comme fullName()
.
Lorsque vous créez un objet à partir d’une classe, il hérite également d’un prototype, et ce prototype a accès à toutes les méthodes de base via la chaîne des prototypes.
Les classes en JavaScript permettent aussi d’utiliser plusieurs fonctionnalités proches de la Programmation Orientée Objet classique.
get et set
Ils permettent de définir des getters et setters pour gérer la manière dont les propriétés de l’objet sont lues et modifiées.
class User {
constructor(firstName, lastName) {
this._firstName = firstName;
this._lastName = lastName;
}
get fullName() {
return `${this._firstName} ${this._lastName}`;
}
set firstName(name) {
this._firstName = name;
}
}
const user = new User('John', 'Doe');
console.log(user.fullName); // Accède à la propriété via un getter
user.firstName = 'Jane'; // Modifie la propriété via un setter
console.log(user.fullName); // Affiche 'Jane Doe'
static
Les méthodes statiques sont des méthodes qui appartiennent à la classe elle-même et non à l’instance.
class MathUtil {
static square(x) {
return x * x;
}
}
console.log(MathUtil.square(4)); // Affiche 16
extends et super
Ces mots-clés permettent de créer des classes dérivées pour implémenter l’héritage entre classes.
class Person {
constructor(firstName, lastName) {
this.firstName = firstName;
this.lastName = lastName;
}
fullName() {
return `${this.firstName} ${this.lastName}`;
}
}
class Employee extends Person {
constructor(firstName, lastName, job) {
super(firstName, lastName); // Appelle le constructeur de la classe parente
this.job = job;
}
getDetails() {
return `${this.fullName()} - ${this.job}`;
}
}
const employee = new Employee('John', 'Doe', 'Developer');
console.log(employee.getDetails()); // Affiche 'John Doe - Developer'