Question 1Dans le constructor d'une classe qui a status = "En attente";, que donne la lecture de this.status ?
constructor et champs de classe — définir les valeurs initiales
Comment le constructor et les champs de classe fixent les valeurs initiales d'une instance : stocker les arguments, l'ordre d'ajout des champs, les arguments omis et le rejet des valeurs invalides.
Un ticket de support contient des valeurs qui changent d'un ticket à l'autre, comme son titre, et des valeurs initiales identiques pour tous, comme l'état « En attente ». Si la classe est mal écrite, des valeurs omises ou invalides se retrouvent stockées dans l'instance.
Cet article traite du constructor, qui reçoit les valeurs passées à la création, et des champs de classe, qui déclarent des valeurs initiales fixes.
Nettoyer les arguments avant de les stocker — le corps du constructor
Les titres envoyés depuis le formulaire de support contiennent parfois des espaces en trop au début ou à la fin. Si tu construis une chaîne d'affichage comme « Alice : Connexion impossible » après la création de l'instance, chaque écran qui l'affiche a besoin de son propre trim et de son propre code d'assemblage.
Dans le corps du constructor, rien ne t'oblige à stocker l'argument tel qu'il arrive. Tu peux stocker une version nettoyée, comme dans this.title = title.trim(), ou une valeur construite à partir de plusieurs arguments. Chaque écran n'a plus qu'à lire les propriétés de l'instance pour obtenir des valeurs déjà propres.
class Ticket {
constructor(title, customerName) {
// Nettoie l'argument avant de le stocker dans this
this.title = title.trim();
this.customerName = customerName;
// Construit la valeur affichée à partir de this, après le nettoyage
this.label = `${this.customerName} : ${this.title}`;
// Avec `${customerName} : ${title}`, les espaces du titre resteraient
}
}
// Passe un titre entouré d'espaces
const ticket = new Ticket(" Connexion impossible ", "Alice");
console.log(ticket.title); // Connexion impossible
console.log(ticket.label); // Alice : Connexion impossible
La ligne du haut lit l'argument title, celle du bas lit this.title après trim. Si tu déplaces la ligne de label au début du constructor, ni this.title ni this.customerName n'ont encore été affectés : label vaut alors undefined : undefined.
Déclarer les valeurs initiales fixes — les champs de classe
Tout nouveau ticket démarre avec l'état « En attente » et zéro commentaire. Si tu définis ces valeurs initiales, qui n'ont rien à voir avec les arguments, dans le constructor avec this.status = "En attente";, elles se mélangent aux lignes qui stockent les arguments, et il faut lire tout le corps pour savoir ce que contient une instance.
Un champ de classe (une propriété déclarée dans le corps de la classe, hors des méthodes, et ajoutée à chaque instance lors du new) s'écrit avec un nom et une valeur initiale seulement, sans this, comme status = "En attente";. Pour le lire depuis le corps du constructor ou depuis une méthode, tu écris this.status, comme pour n'importe quelle autre propriété.
class Ticket {
// Les valeurs initiales indépendantes des arguments vont dans des champs
status = "En attente";
comments = [];
constructor(title) {
this.title = title;
this.summary = `[${this.status}] ${title}`; // Les valeurs des champs sont déjà lisibles
}
}
const first = new Ticket("Connexion impossible");
const second = new Ticket("Facture non reçue");
console.log(first.summary); // [En attente] Connexion impossible
// comments est un tableau distinct, créé à chaque new
first.comments.push("Client invité à redémarrer");
console.log(first.comments.length); // 1
console.log(second.comments.length); // 0
new, les champs sont ajoutés d'abord, puis le corps du constructor s'exécute. Le corps peut donc déjà lire les valeurs des champs.L'étape ① est refaite à chaque new : comments = [] devient donc un tableau distinct pour chaque instance, et un commentaire ajouté à first ne se retrouve pas dans second. C'est pour cela que second.comments.length reste à 0.
this. devant un champ : SyntaxError
Si tu écris this.status = "En attente"; à l'endroit des champs (hors du constructor), tu obtiens SyntaxError: Unexpected token '.' et aucune ligne ne s'exécute. Ajouter let ou const provoque aussi une SyntaxError. Un champ, c'est seulement un nom et une valeur initiale.
Choisir la valeur d'un argument omis — les paramètres par défaut
La plupart des tickets ont la priorité « Normale », et tu veux passer « Urgente » seulement quand c'est pressé. Si tu écris le champ priority = "Normale"; et que tu ajoutes aussi this.priority = priority; dans le corps, un ticket créé sans priorité ne se retrouve pas avec « Normale ».
Un paramètre par défaut (la valeur utilisée quand un argument n'est pas passé), déjà vu dans l'article sur les paramètres par défaut et les paramètres du reste, fonctionne aussi dans un constructor : écris priority = "Normale" dans la liste des paramètres. Un argument omis ou undefined est remplacé par la valeur par défaut avant que le corps s'exécute : this.priority = priority reçoit donc « Normale ».
// Une valeur par défaut dans le champ, et l'argument affecté dans le corps
class DraftTicket {
priority = "Normale";
constructor(title, priority) {
this.title = title;
this.priority = priority; // À droite, l'argument priority (undefined s'il est omis)
}
}
console.log(new DraftTicket("Connexion impossible").priority); // undefined
// Pour une valeur qu'un argument peut changer, utilise un paramètre par défaut
class Ticket {
constructor(title, priority = "Normale") {
this.title = title;
this.priority = priority;
}
}
console.log(new Ticket("Connexion impossible").priority); // Normale
console.log(new Ticket("Facture non reçue", "Urgente").priority); // Urgente
undefined de l'argument. C'est la valeur affectée dans le corps qui reste à la fin.Mets dans un paramètre par défaut une valeur initiale que l'appelant peut remplacer, et dans un champ celle qui ne dépend pas des arguments. Pour une valeur qui dépend d'une condition sur les arguments, comme les frais de port de l'exercice 2, utilise un if dans le corps pour modifier la valeur initiale du champ. Le tableau ci-dessous montre ce qui reste dans priority selon l'approche, avec ou sans « Urgente », y compris une version qui ne l'affecte jamais dans le corps.
| Approche | Titre seul | Avec « Urgente » |
|---|---|---|
| Champ seul (sans affectation) | Normale | Normale (argument ignoré) |
| Champ + this.priority = priority | undefined | Urgente |
| Paramètre priority = "Normale" | Normale | Urgente |
Refuser les valeurs invalides — throw dans le constructor
Si tu te retrouves avec un ticket au titre vide, ou avec une priorité qui ne fait pas partie des valeurs prévues, comme « Haute », la liste affiche une ligne vide, et le ticket est oublié quand tu comptes les tickets « Urgente ». Même si tu écris une fonction séparée pour vérifier les tickets après leur création, tout écran qui oublie de l'appeler continue d'utiliser l'instance invalide.
Pour la validation à la création (vérifier, au moment où tu crées une instance, que les valeurs reçues respectent les règles), écris un if dans le constructor et lève une exception avec throw new Error(...) quand une valeur n'est pas conforme. Une fois l'exception levée, l'expression new ne renvoie aucune instance.
class Ticket {
constructor(title, priority = "Normale") {
// Rejette les valeurs invalides par une exception, avant qu'elles atteignent this
if (title.trim() === "") {
throw new Error("Le titre est vide");
}
if (priority !== "Normale" && priority !== "Urgente") {
throw new Error(`La priorité doit être Normale ou Urgente : ${priority}`);
}
this.title = title.trim();
this.priority = priority;
}
}
try {
const ticket = new Ticket("Connexion impossible", "Haute");
console.log(ticket.title); // Cette ligne ne s'exécute jamais
} catch (error) {
console.log(error.message); // La priorité doit être Normale ou Urgente : Haute
}
const ticket = new Ticket(...)— la partie droite lève une exception,ticketne reçoit rienconsole.log(ticket.title)— ne s'exécute jamais
- Vérification du titre — non vide, elle passe
- Vérification de la priorité — elle vaut
"Haute", doncthrow this.title = ...— plus rien ne s'exécute à partir d'ici
error.message— « La priorité doit être Normale ou Urgente : Haute »
new, saute le reste du try et arrive dans catch. L'instance invalide n'arrive dans aucune variable.Avec la vérification dans le constructor, aucun ticket ne peut y échapper, quel que soit le nombre d'endroits qui appellent new Ticket(...). Si tu inclus la valeur refusée dans le message de l'exception, le bloc catch peut aussi afficher quelle valeur était invalide.
Les affectations après la création ne sont pas vérifiées
La vérification du constructor ne s'exécute que pendant new. Si tu écris ticket.priority = "Haute"; après la création du ticket, aucune erreur ne survient et la valeur est simplement remplacée. L'article sur les getters et setters montre comment vérifier la valeur à chaque affectation.
Vérification des connaissances
Répondez à chaque question une par une.
Question 2Une classe n'a que le champ priority = "Normale"; et ne l'affecte pas dans le corps. Que se passe-t-il si tu passes « Urgente » ?
Question 3Dans un try, le constructor lève une exception pendant const ticket = new Ticket(""). Que se passe-t-il ?