Cours JavaScript et TypeScript · Module 5: JavaScript avancé
Les modules ES (import/export)
Dans cette leçon11
Bienvenue à nouveau à Jurassic Park ! Après avoir bâti des fondations solides en JavaScript et appris les techniques asynchrones, il est temps d'explorer comment organiser le code en projets plus grands et évolutifs. Dans un monde aussi complexe que Jurassic Park, on a besoin d'une structure bien organisée pour garantir la sécurité et l'efficacité du système.
La modularisation du code en JavaScript
Imagine gérer Jurassic Park sans le diviser en équipes et en départements - tout serait chaotique et dangereux ! C'est pareil pour le code - quand tout vit dans un seul fichier, ça devient vite illisible et difficile à maintenir.
Les modules ES (ECMAScript Modules) constituent le système de modules standard de JavaScript, qui te permet de :
- Découper le code en morceaux plus petits et plus faciles à gérer
- Contrôler quels éléments sont accessibles à l'extérieur d'un module
- Définir les dépendances entre les différentes parties d'un programme
Exporter des éléments depuis les modules
Commençons par créer quelques modules de base pour notre système de gestion de Jurassic Park :
1. Export par défaut (default export)
Quand on a un élément principal à exporter, on utilise un export par défaut :
1// dinosaur.js - Modèle de dinosaure
2class Dinosaur {
3 constructor(name, species, diet, dangerLevel) {
4 this.name = name;
5 this.species = species;
6 this.diet = diet;
7 this.dangerLevel = dangerLevel;
8 this.health = 100;
9 this.isContained = true;
10 }
11
12 feed() {
13 this.health = Math.min(100, this.health + 20);
14 return `${this.name} a été nourri. Niveau de santé : ${this.health}%`;
15 }
16
17 checkStatus() {
18 return {
19 name: this.name,
20 health: this.health,
21 isContained: this.isContained,
22 warning: this.dangerLevel > 7 ? "NIVEAU DE DANGER ÉLEVÉ" : ""
23 };
24 }
25}
26
27// Export par défaut - une seule classe/fonction/objet par fichier
28export default Dinosaur;2. Exports nommés (named exports)
Quand on a plusieurs éléments à exporter, on utilise des exports nommés :
1// securityUtils.js - Fonctions utilitaires de sécurité
2export const SECURITY_LEVELS = {
3 GREEN: "normal",
4 YELLOW: "elevated",
5 ORANGE: "high",
6 RED: "critical"
7};
8
9export function checkFenceStatus(sectorId) {
10 // Simule la vérification de l'état des clôtures dans un secteur donné
11 const status = Math.random() > 0.1 ? "active" : "failure";
12 return {
13 sector: sectorId,
14 status,
15 timestamp: new Date().toISOString()
16 };
17}
18
19export function triggerAlarm(sector, reason) {
20 console.log(`ALARME ! Secteur ${sector} : ${reason}`);
21 // Logique d'activation de l'alarme
22 return {
23 success: true,
24 alarmId: "ALR-" + Math.floor(Math.random() * 10000)
25 };
26}
27
28// On peut aussi exporter une fonction par défaut en plus des exports nommés
29export default function getSecurityStatus() {
30 // Renvoie l'état de sécurité global du parc
31 return {
32 level: SECURITY_LEVELS.GREEN,
33 activeAlarms: 0,
34 lastChecked: new Date().toISOString()
35 };
36}3. Exporter des variables définies au préalable
On peut aussi définir d'abord nos variables, fonctions ou classes, puis les exporter à la fin du fichier :
1// parkStats.js - Statistiques de Jurassic Park
2const totalVisitors = 0;
3const revenue = 0;
4const incidents = [];
5
6function addVisitors(count) {
7 totalVisitors += count;
8 return totalVisitors;
9}
10
11function addRevenue(amount) {
12 revenue += amount;
13 return revenue;
14}
15
16function recordIncident(type, location, description) {
17 const incident = {
18 id: incidents.length + 1,
19 type,
20 location,
21 description,
22 timestamp: new Date().toISOString()
23 };
24 incidents.push(incident);
25 return incident;
26}
27
28function getDailyStats() {
29 return {
30 totalVisitors,
31 revenue,
32 incidentCount: incidents.length
33 };
34}
35
36// Exporter plusieurs éléments d'un coup
37export {
38 addVisitors,
39 addRevenue,
40 recordIncident,
41 getDailyStats
42};
43
44// On peut aussi renommer un élément exporté
45export { recordIncident as logParkIncident };Importer des éléments depuis les modules
Après avoir créé des modules, il est temps de les utiliser dans l'application principale :
1. Import par défaut
1// app.js
2import Dinosaur from './dinosaur.js';
3
4// Crée de nouvelles instances de dinosaure
5const trex = new Dinosaur("Rex", "Tyrannosaurus", "carnivore", 9);
6const brachi = new Dinosaur("Longneck", "Brachiosaurus", "herbivore", 4);
7
8console.log(trex.checkStatus());
9console.log(brachi.feed());2. Import nommé
1// securityMonitor.js
2import { checkFenceStatus, triggerAlarm, SECURITY_LEVELS } from './securityUtils.js';
3
4// Utilise les fonctions et constantes importées
5function monitorSecurity() {
6 const sectors = ["A1", "B2", "C3", "D4"];
7
8 // Vérifie chaque secteur
9 sectors.forEach(sector => {
10 const fenceStatus = checkFenceStatus(sector);
11
12 if (fenceStatus.status === "failure") {
13 const alarmResult = triggerAlarm(
14 sector,
15 "Panne de clôture électrique !"
16 );
17 console.log(`Alarme ${alarmResult.alarmId} déclenchée dans le secteur ${sector}`);
18
19 document.querySelector("#securityStatus").textContent = SECURITY_LEVELS.RED;
20 }
21 });
22}
23
24setInterval(monitorSecurity, 60000); // Vérifie toutes les minutes3. Import par défaut et import nommé combinés
1// dashboard.js
2import getSecurityStatus, { SECURITY_LEVELS, checkFenceStatus } from './securityUtils.js';
3
4// Utilise l'import par défaut
5const parkStatus = getSecurityStatus();
6console.log("État de sécurité :", parkStatus.level);
7
8// Utilise les imports nommés
9if (parkStatus.level === SECURITY_LEVELS.RED) {
10 // Vérifie immédiatement tous les secteurs
11 ["A1", "B2", "C3", "D4"].forEach(sector => {
12 console.log(`Vérification du secteur ${sector} : `, checkFenceStatus(sector));
13 });
14}4. Import avec alias
1// incidentReport.js
2import { recordIncident as logIncident } from './parkStats.js';
3
4// Utilise la fonction importée sous son nouveau nom
5function reportEmergency(location, details) {
6 logIncident("EMERGENCY", location, details);
7 // Logique supplémentaire de gestion d'urgence
8}5. Importer tout sous forme d'objet
1// adminPanel.js
2import * as ParkStats from './parkStats.js';
3
4// Accède à toutes les fonctions du module via l'objet
5function generateDailyReport() {
6 const visitorCount = ParkStats.addVisitors(120); // Ajoute 120 visiteurs
7 const dailyRevenue = ParkStats.addRevenue(15000); // Ajoute 15 000 $ de revenus
8
9 const stats = ParkStats.getDailyStats();
10
11 return `
12 Rapport quotidien de Jurassic Park :
13 - Nombre de visiteurs : ${stats.totalVisitors}
14 - Revenus : ${stats.revenue} $
15 - Incidents : ${stats.incidentCount}
16 `;
17}Agréger et ré-exporter des modules
Dans les grands projets, il est souvent utile de créer des points d'entrée qui agrègent et ré-exportent les fonctionnalités de plusieurs petits modules :
1// models/index.js - Agrège tous les modèles
2export { default as Dinosaur } from './dinosaur.js';
3export { default as Employee } from './employee.js';
4export { default as Facility } from './facility.js';
5export { default as Visitor } from './visitor.js';Cela nous permet d'importer tous les modèles depuis un seul point d'entrée :
1// main.js
2import { Dinosaur, Employee, Facility } from './models/index.js';
3
4// On peut maintenant utiliser tous les modèles
5const rex = new Dinosaur("Rex", "Tyrannosaurus", "carnivore", 9);
6const lab = new Facility("InGen Labs", "B3", 12);
7const scientist = new Employee("Dr. Wu", "Chief Geneticist", "lab");L'import dynamique de modules
Les modules ES offrent aussi un mécanisme d'import dynamique, permettant de charger les modules à la demande :
1// emergencySystem.js
2async function handleEmergency(type) {
3 let emergencyModule;
4
5 switch(type) {
6 case "dinosaurEscape":
7 emergencyModule = await import('./emergencies/dinosaurEscape.js');
8 break;
9 case "powerOutage":
10 emergencyModule = await import('./emergencies/powerOutage.js');
11 break;
12 case "weatherAlert":
13 emergencyModule = await import('./emergencies/weatherAlert.js');
14 break;
15 default:
16 emergencyModule = await import('./emergencies/generalEmergency.js');
17 }
18
19 // Exécute la procédure d'urgence depuis le module chargé
20 emergencyModule.initiateProtocol();
21}
22
23// Bouton de l'interface pour déclencher la procédure d'urgence
24document.querySelector("#emergencyButton").addEventListener("click", () => {
25 const emergencyType = document.querySelector("#emergencyType").value;
26 handleEmergency(emergencyType);
27});Les modules ES dans le navigateur
Pour utiliser les modules ES directement dans le navigateur, on doit ajouter l'attribut type="module" à la balise script :
1<!DOCTYPE html>
2<html>
3<head>
4 <title>Panneau de contrôle de Jurassic Park</title>
5</head>
6<body>
7 <h1>Panneau de contrôle de Jurassic Park</h1>
8 <div id="securityStatus"></div>
9 <select id="emergencyType">
10 <option value="dinosaurEscape">Évasion de dinosaure</option>
11 <option value="powerOutage">Panne de courant</option>
12 <option value="weatherAlert">Alerte météo</option>
13 </select>
14 <button id="emergencyButton">Activer la procédure d'urgence</button>
15
16 <!-- Script principal utilisant les modules -->
17 <script type="module" src="./app.js"></script>
18</body>
19</html>Les avantages d'une approche modulaire
Organiser les applications avec les modules ES offre de nombreux avantages :
- Encapsulation - chaque module a son propre espace de noms, ce qui évite les conflits de noms
- Réutilisabilité - les modules peuvent être facilement réutilisés dans différentes parties de l'application
- Organisation - le code est plus facile à comprendre et à maintenir lorsqu'il est découpé en parties logiques
- Collaboration en équipe - différents membres de l'équipe peuvent travailler sur des modules séparés
- Chargement paresseux (lazy loading) - les modules peuvent être chargés uniquement quand on en a besoin
- Meilleure gestion des dépendances - des dépendances clairement définies entre les modules
Exemple pratique : système de surveillance des dinosaures
Voyons comment on pourrait organiser un système plus vaste de surveillance des dinosaures pour Jurassic Park en utilisant des modules :
1// models/dinosaur.js
2export default class Dinosaur {
3 // ... implémentation de la classe Dinosaur (comme ci-dessus)
4}
5
6// services/dinoTracking.js
7import Dinosaur from '../models/dinosaur.js';
8
9export async function getAllDinosaurs() {
10 // Récupère les données des dinosaures depuis l'API
11 const response = await fetch('/api/dinosaurs');
12 const data = await response.json();
13
14 // Convertit les données brutes en instances de la classe Dinosaur
15 return data.map(dino => new Dinosaur(
16 dino.name,
17 dino.species,
18 dino.diet,
19 dino.dangerLevel
20 ));
21}
22
23export async function getDinosaursByDangerLevel(level) {
24 const allDinos = await getAllDinosaurs();
25 return allDinos.filter(dino => dino.dangerLevel >= level);
26}
27
28// services/securitySystem.js
29export async function getActiveFences() {
30 // Récupère les données des clôtures actives
31 const response = await fetch('/api/fences/active');
32 return response.json();
33}
34
35export async function activateSectorLockdown(sectorId) {
36 // Active le confinement dans un secteur donné
37 const response = await fetch(`/api/sectors/${sectorId}/lockdown`, {
38 method: 'POST'
39 });
40 return response.json();
41}
42
43// utils/alertSystem.js
44export const ALERT_LEVELS = {
45 INFO: 'info',
46 WARNING: 'warning',
47 DANGER: 'danger',
48 CRITICAL: 'critical'
49};
50
51export function showAlert(message, level = ALERT_LEVELS.INFO) {
52 const alertElement = document.createElement('div');
53 alertElement.className = `alert alert-${level}`;
54 alertElement.textContent = message;
55
56 document.querySelector('#alertContainer').appendChild(alertElement);
57
58 // Retire l'alerte après 5 secondes (sauf si elle est critique)
59 if (level !== ALERT_LEVELS.CRITICAL) {
60 setTimeout(() => {
61 alertElement.remove();
62 }, 5000);
63 }
64}
65
66// controllers/monitoringDashboard.js
67import { getAllDinosaurs, getDinosaursByDangerLevel } from '../services/dinoTracking.js';
68import { getActiveFences, activateSectorLockdown } from '../services/securitySystem.js';
69import { showAlert, ALERT_LEVELS } from '../utils/alertSystem.js';
70
71export async function initializeDashboard() {
72 try {
73 // Récupère les données des dinosaures et l'état des clôtures
74 const [allDinos, activeFences] = await Promise.all([
75 getAllDinosaurs(),
76 getActiveFences()
77 ]);
78
79 // Trouve les dinosaures dangereux
80 const dangerousDinos = await getDinosaursByDangerLevel(8);
81
82 // Affiche les données sur le tableau de bord
83 renderDinosaurTable(allDinos);
84 renderSecurityStatus(activeFences);
85
86 // Affiche des alertes pour les dinosaures dangereux
87 if (dangerousDinos.length > 0) {
88 showAlert(
89 `ATTENTION : ${dangerousDinos.length} dinosaures au niveau de danger élevé`,
90 ALERT_LEVELS.WARNING
91 );
92 }
93
94 // Configure les écouteurs d'événements d'urgence
95 setupEmergencyHandlers();
96
97 } catch (error) {
98 showAlert(`Erreur d'initialisation du tableau de bord : ${error.message}`, ALERT_LEVELS.DANGER);
99 }
100}
101
102function renderDinosaurTable(dinosaurs) {
103 // Logique de rendu du tableau des dinosaures
104}
105
106function renderSecurityStatus(fences) {
107 // Logique de rendu de l'état de sécurité
108}
109
110function setupEmergencyHandlers() {
111 // Logique de configuration des gestionnaires d'événements d'urgence
112 document.querySelector('#emergencyLockdown').addEventListener('click', async () => {
113 const sector = document.querySelector('#sectorSelect').value;
114 try {
115 await activateSectorLockdown(sector);
116 showAlert(`Confinement du secteur ${sector} activé`, ALERT_LEVELS.WARNING);
117 } catch (error) {
118 showAlert(`Échec de l'activation du confinement : ${error.message}`, ALERT_LEVELS.CRITICAL);
119 }
120 });
121}
122
123// app.js - Fichier principal de l'application
124import { initializeDashboard } from './controllers/monitoringDashboard.js';
125
126// Initialise l'application une fois le DOM prêt
127document.addEventListener('DOMContentLoaded', () => {
128 initializeDashboard();
129
130 // Logique d'initialisation supplémentaire
131 console.log('Système de surveillance de Jurassic Park démarré');
132});Compatibilité navigateur et configuration de Webpack
Les navigateurs modernes prennent en charge les modules ES nativement, mais pour une compatibilité totale avec les navigateurs plus anciens, on utilise souvent des outils comme Webpack ou Rollup pour regrouper nos modules en code compatible avec les anciens navigateurs.
Configuration Webpack de base pour les modules ES
1// webpack.config.js
2const path = require('path');
3
4module.exports = {
5 entry: './src/app.js',
6 output: {
7 filename: 'bundle.js',
8 path: path.resolve(__dirname, 'dist')
9 },
10 module: {
11 rules: [
12 {
13 test: /\.js$/,
14 exclude: /node_modules/,
15 use: {
16 loader: 'babel-loader',
17 options: {
18 presets: ['@babel/preset-env']
19 }
20 }
21 }
22 ]
23 }
24};Bonnes pratiques pour travailler avec les modules
- Responsabilité unique - chaque module ne devrait avoir qu'une seule responsabilité clairement définie
- Petits modules - garde les modules petits et concentrés sur une tâche précise
- Nommage cohérent - utilise des conventions de nommage cohérentes pour les fichiers de modules
- Dépendances explicites - toutes les dépendances doivent être clairement définies dans les imports
- Limiter les mutations d'état - évite de modifier l'état global dans les modules
- Documentation - ajoute des commentaires JSDoc aux fonctions et classes exportées
- Structure de dossiers - organise les modules dans une structure de dossiers logique (par ex. models, services, utils)
Résumé
Les modules ES sont un mécanisme puissant d'organisation du code JavaScript qui te permet de créer des applications modulaires et bien organisées. Dans un monde aussi complexe que Jurassic Park, où chaque erreur peut avoir des conséquences catastrophiques, une bonne organisation du code est essentielle pour maintenir la sécurité et l'efficacité.
Dans l'exercice suivant, nous examinerons un système de modules alternatif - CommonJS, très répandu dans l'environnement Node.js, idéal pour construire la partie serveur de notre système de gestion de Jurassic Park.
Code de cette leçon : main.js
1// Modules ES dans Jurassic Park
2// Fichier principal du systeme de gestion du parc
3
4console.log("Jurassic Park Management System");
5console.log("Demonstration des modules ES (import/export)\n");
6
7// ===========================================
8// Simulation des imports (en vrai ES6, ce seraient des fichiers separes)
9// ===========================================
10
11// === dinosaur.js - Modele de dinosaure ===
12class Dinosaur {
13 constructor(name, species, diet, dangerLevel) {
14 this.name = name;
15 this.species = species;
16 this.diet = diet;
17 this.dangerLevel = dangerLevel; // 1-10
18 this.isActive = true;
19 this.lastFed = new Date();
20 this.energy = 100;
21 }
22
23 feed() {
24 this.energy = Math.min(100, this.energy + 20);
25 this.lastFed = new Date();
26 return `${this.name} a ete nourri. Energie : ${this.energy}%`;
27 }
28
29 roar() {
30 const sounds = {
31 'carnivore': 'ROAAAAR!',
32 'herbivore': 'Hoooonk!',
33 'omnivore': 'Grrrrooo!'
34 };
35 return `${this.name}: ${sounds[this.diet] || 'Hmm?'}`;
36 }
37
38 getInfo() {
39 return {
40 name: this.name,
41 species: this.species,
42 diet: this.diet,
43 dangerLevel: this.dangerLevel,
44 energy: this.energy,
45 status: this.isActive ? 'Active' : 'Sleeping'
46 };
47 }
48}
49
50// Default export
51const DinosaurClass = Dinosaur;
52
53// === security.js - Systeme de securite ===
54const SECURITY_LEVELS = {
55 GREEN: 1,
56 YELLOW: 2,
57 ORANGE: 3,
58 RED: 4,
59 CRITICAL: 5
60};
61
62function calculateSecurityLevel(dinosaurs) {
63 const maxDanger = Math.max(...dinosaurs.map(d => d.dangerLevel));
64 const activeCarnivores = dinosaurs.filter(d => d.diet === 'carnivore' && d.isActive).length;
65
66 if (maxDanger >= 9 || activeCarnivores >= 3) return SECURITY_LEVELS.CRITICAL;
67 if (maxDanger >= 7 || activeCarnivores >= 2) return SECURITY_LEVELS.RED;
68 if (maxDanger >= 5 || activeCarnivores >= 1) return SECURITY_LEVELS.ORANGE;
69 if (maxDanger >= 3) return SECURITY_LEVELS.YELLOW;
70 return SECURITY_LEVELS.GREEN;
71}
72
73function getSecurityMessage(level) {
74 const messages = {
75 [SECURITY_LEVELS.GREEN]: "Parc securise",
76 [SECURITY_LEVELS.YELLOW]: "Vigilance accrue",
77 [SECURITY_LEVELS.ORANGE]: "Menace moyenne",
78 [SECURITY_LEVELS.RED]: "Menace elevee",
79 [SECURITY_LEVELS.CRITICAL]: "ETAT CRITIQUE"
80 };
81 return messages[level] || "Niveau inconnu";
82}
83
84// Exports nommes (named exports)
85const SecurityModule = {
86 SECURITY_LEVELS,
87 calculateSecurityLevel,
88 getSecurityMessage
89};
90
91// === enclosure.js - Gestion des enclos ===
92class Enclosure {
93 constructor(id, name, capacity, type) {
94 this.id = id;
95 this.name = name;
96 this.capacity = capacity;
97 this.type = type; // 'carnivore', 'herbivore', 'mixed'
98 this.dinosaurs = [];
99 this.isLocked = true;
100 this.maintenanceMode = false;
101 }
102
103 addDinosaur(dinosaur) {
104 if (this.dinosaurs.length >= this.capacity) {
105 return `Erreur : l'enclos ${this.name} est plein`;
106 }
107
108 if (this.type === 'carnivore' && dinosaur.diet !== 'carnivore') {
109 return `Erreur : un enclos pour carnivores ne peut pas accueillir un ${dinosaur.diet}`;
110 }
111
112 if (this.type === 'herbivore' && dinosaur.diet === 'carnivore') {
113 return `Erreur : un enclos pour herbivores ne peut pas accueillir de carnivores`;
114 }
115
116 this.dinosaurs.push(dinosaur);
117 return `${dinosaur.name} ajoute a l'enclos ${this.name}`;
118 }
119
120 removeDinosaur(dinosaurName) {
121 const index = this.dinosaurs.findIndex(d => d.name === dinosaurName);
122 if (index === -1) {
123 return `Erreur : le dinosaure ${dinosaurName} ne se trouve pas dans cet enclos`;
124 }
125
126 const removed = this.dinosaurs.splice(index, 1)[0];
127 return `${removed.name} retire de l'enclos ${this.name}`;
128 }
129
130 feedAll() {
131 const results = this.dinosaurs.map(dinosaur => dinosaur.feed());
132 return results;
133 }
134
135 getStatus() {
136 return {
137 id: this.id,
138 name: this.name,
139 capacity: this.capacity,
140 occupied: this.dinosaurs.length,
141 type: this.type,
142 isLocked: this.isLocked,
143 maintenanceMode: this.maintenanceMode,
144 dinosaurs: this.dinosaurs.map(d => d.getInfo())
145 };
146 }
147
148 lock() {
149 this.isLocked = true;
150 return `Enclos ${this.name} ferme`;
151 }
152
153 unlock() {
154 this.isLocked = false;
155 return `Enclos ${this.name} ouvert`;
156 }
157}
158
159const EnclosureClass = Enclosure;
160
161// === utils.js - Fonctions utilitaires ===
162function formatTime(date) {
163 return date.toLocaleTimeString('pl-PL');
164}
165
166function generateId() {
167 return 'ID-' + Math.random().toString(36).substr(2, 9).toUpperCase();
168}
169
170function logAction(action, details = '') {
171 const timestamp = formatTime(new Date());
172 const logEntry = `[${timestamp}] ${action} ${details}`;
173 console.log(logEntry);
174 return logEntry;
175}
176
177function calculateDistance(point1, point2) {
178 const dx = point2.x - point1.x;
179 const dy = point2.y - point1.y;
180 return Math.sqrt(dx * dx + dy * dy);
181}
182
183// Export de plusieurs fonctions
184const UtilsModule = {
185 formatTime,
186 generateId,
187 logAction,
188 calculateDistance
189};
190
191// === park-manager.js - Systeme de gestion principal ===
192class ParkManager {
193 constructor() {
194 this.enclosures = new Map();
195 this.dinosaurs = new Map();
196 this.securityLevel = SecurityModule.SECURITY_LEVELS.GREEN;
197 this.isOpen = false;
198 this.visitors = 0;
199 }
200
201 // Gestion des enclos
202 createEnclosure(name, capacity, type) {
203 const id = UtilsModule.generateId();
204 const enclosure = new EnclosureClass(id, name, capacity, type);
205 this.enclosures.set(id, enclosure);
206
207 UtilsModule.logAction('ENCLOSURE_CREATED', `${name} (capacity: ${capacity}, type: ${type})`);
208 return enclosure;
209 }
210
211 // Gestion des dinosaures
212 addDinosaur(name, species, diet, dangerLevel, enclosureId) {
213 const dinosaur = new DinosaurClass(name, species, diet, dangerLevel);
214 this.dinosaurs.set(name, dinosaur);
215
216 if (enclosureId && this.enclosures.has(enclosureId)) {
217 const enclosure = this.enclosures.get(enclosureId);
218 const result = enclosure.addDinosaur(dinosaur);
219 UtilsModule.logAction('DINOSAUR_ADDED', `${name} -> ${enclosure.name}`);
220 console.log(result);
221 }
222
223 this.updateSecurityLevel();
224 return dinosaur;
225 }
226
227 // Mise a jour du niveau de securite
228 updateSecurityLevel() {
229 const allDinosaurs = Array.from(this.dinosaurs.values());
230 this.securityLevel = SecurityModule.calculateSecurityLevel(allDinosaurs);
231
232 const message = SecurityModule.getSecurityMessage(this.securityLevel);
233 UtilsModule.logAction('SECURITY_UPDATE', message);
234 }
235
236 // Rapport sur l'etat du parc
237 getParkStatus() {
238 const enclosureStatuses = Array.from(this.enclosures.values()).map(e => e.getStatus());
239 const dinosaurCount = this.dinosaurs.size;
240 const securityMessage = SecurityModule.getSecurityMessage(this.securityLevel);
241
242 return {
243 isOpen: this.isOpen,
244 visitors: this.visitors,
245 dinosaurCount,
246 enclosureCount: this.enclosures.size,
247 securityLevel: this.securityLevel,
248 securityMessage,
249 enclosures: enclosureStatuses,
250 timestamp: UtilsModule.formatTime(new Date())
251 };
252 }
253
254 // Ouverture/fermeture du parc
255 openPark() {
256 if (this.securityLevel <= SecurityModule.SECURITY_LEVELS.YELLOW) {
257 this.isOpen = true;
258 UtilsModule.logAction('PARK_OPENED', 'Park open for visitors');
259 return "Jurassic Park ouvert !";
260 } else {
261 return "Le parc ne peut pas ouvrir - niveau de danger trop eleve";
262 }
263 }
264
265 closePark() {
266 this.isOpen = false;
267 this.visitors = 0;
268 UtilsModule.logAction('PARK_CLOSED', 'Park closed');
269 return "Jurassic Park ferme";
270 }
271
272 // Nourrir tous les dinosaures
273 feedAllDinosaurs() {
274 const results = [];
275
276 for (const enclosure of this.enclosures.values()) {
277 const feedResults = enclosure.feedAll();
278 results.push(...feedResults);
279 }
280
281 UtilsModule.logAction('MASS_FEEDING', `Fed ${results.length} dinosaurs`);
282 return results;
283 }
284
285 // Situation d'urgence
286 emergencyProtocol() {
287 UtilsModule.logAction('EMERGENCY', 'Emergency protocol activated!');
288
289 // Fermer le parc
290 this.closePark();
291
292 // Fermer tous les enclos
293 for (const enclosure of this.enclosures.values()) {
294 enclosure.lock();
295 }
296
297 console.log("EMERGENCY PROTOCOL ACTIVATED!");
298 console.log("- Park closed");
299 console.log("- Tous les enclos verrouilles");
300 console.log("- Evacuation des visiteurs en cours");
301
302 return "Protocole d'urgence active";
303 }
304}
305
306// ===========================================
307// DEMONSTRATION DU SYSTEME
308// ===========================================
309console.log("=== INITIALISATION DU SYSTEME DU PARC ===\n");
310
311// Creation du gestionnaire du parc
312const parkManager = new ParkManager();
313
314// Creation des enclos
315console.log("Creation des enclos...");
316const carnivorePaddock = parkManager.createEnclosure("Paddock A - Carnivores", 3, "carnivore");
317const herbivorePaddock = parkManager.createEnclosure("Paddock B - Herbivores", 5, "herbivore");
318const mixedPaddock = parkManager.createEnclosure("Paddock C - Mieszany", 4, "mixed");
319
320console.log("\nAjout des dinosaures...");
321
322// Ajout des dinosaures
323const trex = parkManager.addDinosaur(
324 "Rexy",
325 "Tyrannosaurus Rex",
326 "carnivore",
327 9,
328 carnivorePaddock.id
329);
330
331const raptor1 = parkManager.addDinosaur(
332 "Blue",
333 "Velociraptor",
334 "carnivore",
335 7,
336 carnivorePaddock.id
337);
338
339const raptor2 = parkManager.addDinosaur(
340 "Charlie",
341 "Velociraptor",
342 "carnivore",
343 7,
344 carnivorePaddock.id
345);
346
347const trice = parkManager.addDinosaur(
348 "Spike",
349 "Triceratops",
350 "herbivore",
351 3,
352 herbivorePaddock.id
353);
354
355const brachi = parkManager.addDinosaur(
356 "Gentle Giant",
357 "Brachiosaurus",
358 "herbivore",
359 2,
360 herbivorePaddock.id
361);
362
363const stego = parkManager.addDinosaur(
364 "Spike Jr",
365 "Stegosaurus",
366 "herbivore",
367 4,
368 mixedPaddock.id
369);
370
371// Test des cris des dinosaures
372console.log("\nTest de communication avec les dinosaures :");
373console.log(trex.roar());
374console.log(raptor1.roar());
375console.log(trice.roar());
376console.log(brachi.roar());
377
378// Report stanu parku
379console.log("\nRAPPORT SUR L'ETAT DU PARC :");
380const status = parkManager.getParkStatus();
381console.log(`Status: ${status.isOpen ? 'Open' : 'Closed'}`);
382console.log(`Dinosaury: ${status.dinosaurCount}`);
383console.log(`Paddocki: ${status.enclosureCount}`);
384console.log(`Security: ${status.securityMessage}`);
385
386// Tentative d'ouverture du parc
387console.log("\nTentative d'ouverture du parc...");
388const openResult = parkManager.openPark();
389console.log(openResult);
390
391// Nourrissage des dinosaures
392console.log("\nNourrissage des dinosaures...");
393const feedingResults = parkManager.feedAllDinosaurs();
394feedingResults.forEach(result => console.log(" " + result));
395
396// Simulation d'une situation d'urgence
397console.log("\nSimulation d'une panne...");
398setTimeout(() => {
399 console.log("\nDANGER DETECTE !");
400 parkManager.emergencyProtocol();
401
402 // Etat apres la panne
403 setTimeout(() => {
404 console.log("\nEtat apres le protocole d'urgence :");
405 const finalStatus = parkManager.getParkStatus();
406 console.log(`Park: ${finalStatus.isOpen ? 'Open' : 'Closed'}`);
407 console.log(`Security: ${finalStatus.securityMessage}`);
408
409 console.log("\nDetails des enclos :");
410 finalStatus.enclosures.forEach(enc => {
411 console.log(` ${enc.name}: ${enc.occupied}/${enc.capacity} dinosaurs, ${enc.isLocked ? 'Closed' : 'Open'}`);
412 });
413 }, 2000);
414}, 3000);
415
416// ===========================================
417// DEMONSTRATION DES DIFFERENTS TYPES D'EXPORTS
418// ===========================================
419console.log("\n=== ES6 EXPORT TYPES ===");
420
421// 1. Export par defaut - une seule chose principale d'un module
422console.log("1. Export par defaut - classe Dinosaur principale");
423const myDino = new DinosaurClass("Test Dino", "Test Species", "omnivore", 5);
424console.log(" Cree :", myDino.name);
425
426// 2. Exports nommes - plusieurs fonctions/objets
427console.log("\n2. Exports nommes - fonctions utilitaires");
428console.log(" Generated ID:", UtilsModule.generateId());
429console.log(" Current time:", UtilsModule.formatTime(new Date()));
430
431// 3. Re-exports - exporter depuis d'autres modules
432console.log("\n3. Exports du module de securite");
433console.log(" Security levels:", Object.keys(SecurityModule.SECURITY_LEVELS));
434
435// 4. Import d'espace de noms - tout comme un seul objet
436console.log("\n4. Utilisation combinee des modules :");
437const testEnclosure = new EnclosureClass("TEST-001", "Test Enclosure", 2, "mixed");
438testEnclosure.addDinosaur(myDino);
439console.log(" Test enclosure created with:", testEnclosure.dinosaurs.length, "dinosaur(s)");
440
441// ===========================================
442// SIMULATION DE VRAIS IMPORTS ES6
443// ===========================================
444console.log("\n=== SIMULATION OF ES6 IMPORTS ===");
445console.log("Dans une vraie application, on utiliserait :");
446console.log("");
447console.log("// main.js");
448console.log("import Dinosaur from './dinosaur.js'; // default import");
449console.log("import { SECURITY_LEVELS, calculateSecurityLevel } from './security.js'; // named imports");
450console.log("import * as Utils from './utils.js'; // namespace import");
451console.log("import Enclosure, { EnclosureType } from './enclosure.js'; // mixed import");
452console.log("");
453console.log("// dinosaur.js");
454console.log("export default class Dinosaur { ... }");
455console.log("");
456console.log("// security.js");
457console.log("export const SECURITY_LEVELS = { ... };");
458console.log("export function calculateSecurityLevel(dinosaurs) { ... }");
459console.log("");
460console.log("// utils.js");
461console.log("export function formatTime(date) { ... }");
462console.log("export function generateId() { ... }");
463console.log("export { formatTime as timeFormatter }; // alias export");
464
465console.log("\nDemonstration des modules ES terminee !");Tu as repéré une erreur dans cette leçon ?
Teste tes connaissances
Réponds aux questions de cette leçon. Choisis une réponse pour voir tout de suite si elle est correcte.
1. Qu'est-ce qu'un module en JavaScript ?
Tâches pratiques dans le jeu
- Tri horizontal
Ordonne les éléments d'un import de module :