Cours JavaScript et TypeScript · Module 2: Fonctions, tableaux et objets

Les méthodes de base des tableaux en JavaScript

22 min de lecture
Dans cette leçon3

Bienvenue de retour à Jurassic Park ! Dans la leçon précédente, tu as appris les bases des tableaux en JavaScript. Nous allons maintenant plonger dans les méthodes de base des tableaux, essentielles pour le travail quotidien avec les données. Ces méthodes te permettent d'ajouter, de retirer et de manipuler des éléments dans les tableaux, ce qui est crucial pour gérer l'inventaire des dinosaures, planifier les repas et organiser le personnel du parc.

Modifier les tableaux - les méthodes mutantes

Commençons par examiner les méthodes qui modifient le tableau original. On les appelle des méthodes mutantes.

1. push() - Ajouter des éléments à la fin d'un tableau

La méthode push() ajoute un ou plusieurs éléments à la fin d'un tableau et renvoie la nouvelle longueur du tableau :

1// Gestion des espèces de dinosaures dans notre enclos
2const dinoEnclosure = ["T-Rex", "Velociraptor"];
3
4// Ajout d'une nouvelle espèce de dinosaure
5dinoEnclosure.push("Dilophosaurus");
6console.log(dinoEnclosure); // ["T-Rex", "Velociraptor", "Dilophosaurus"]
7
8// Ajout de plusieurs espèces à la fois
9const newLength = dinoEnclosure.push("Gallimimus", "Compsognathus");
10console.log(dinoEnclosure);
11// ["T-Rex", "Velociraptor", "Dilophosaurus", "Gallimimus", "Compsognathus"]
12console.log(`Nombre actuel d'espèces dans l'enclos : ${newLength}`); // 5

Quand utiliser push() :

  • Quand tu dois ajouter un ou plusieurs éléments à la fin d'un tableau
  • Quand tu veux connaître la nouvelle longueur du tableau après l'ajout d'éléments
  • Quand l'ordre des éléments compte et que le nouvel élément doit aller à la fin

2. pop() - Retirer le dernier élément

La méthode pop() retire le dernier élément d'un tableau et renvoie cet élément :

1// Liste des dinosaures dans notre enclos
2const dinoEnclosure = ["T-Rex", "Velociraptor", "Dilophosaurus", "Compsognathus"];
3
4// Déplacement du dernier dinosaure vers un nouvel enclos
5const removedDino = dinoEnclosure.pop();
6console.log(`Dinosaure déplacé : ${removedDino}`); // "Compsognathus"
7console.log("Dinosaures restants :", dinoEnclosure); // ["T-Rex", "Velociraptor", "Dilophosaurus"]
8
9// On peut continuer à en retirer
10const anotherRemovedDino = dinoEnclosure.pop();
11console.log(`Autre dinosaure déplacé : ${anotherRemovedDino}`); // "Dilophosaurus"
12console.log("Contenu actuel de l'enclos :", dinoEnclosure); // ["T-Rex", "Velociraptor"]

Quand utiliser pop() :

  • Quand tu dois retirer le dernier élément d'un tableau
  • Quand tu as besoin de récupérer la valeur de l'élément retiré
  • Quand tu implémentes des structures de données de type pile (LIFO - Last In, First Out)

3. unshift() - Ajouter des éléments au début

La méthode unshift() ajoute un ou plusieurs éléments au début d'un tableau et renvoie la nouvelle longueur du tableau :

1// File d'attente des dinosaures en attente d'examen
2const dinoQueue = ["Velociraptor", "Triceratops"];
3
4// Ajout prioritaire du T-Rex en tête de file
5dinoQueue.unshift("T-Rex");
6console.log("File actuelle :", dinoQueue); // ["T-Rex", "Velociraptor", "Triceratops"]
7
8// Ajout de plusieurs dinosaures à la fois en tête de file
9const newQueueSize = dinoQueue.unshift("Brachiosaurus", "Stegosaurus");
10console.log("File actuelle :", dinoQueue);
11// ["Brachiosaurus", "Stegosaurus", "T-Rex", "Velociraptor", "Triceratops"]
12console.log(`Nombre de dinosaures dans la file : ${newQueueSize}`); // 5

Quand utiliser unshift() :

  • Quand tu veux ajouter un élément au début d'un tableau
  • Quand tu implémentes des files de priorité où les éléments les plus prioritaires vont en tête
  • Quand tu dois connaître la nouvelle longueur du tableau

4. shift() - Retirer le premier élément

La méthode shift() retire le premier élément d'un tableau et renvoie cet élément :

1// File d'attente des dinosaures en attente d'examen
2const dinoQueue = ["T-Rex", "Velociraptor", "Triceratops", "Stegosaurus"];
3
4// Récupération du premier dinosaure pour l'examen
5const nextDino = dinoQueue.shift();
6console.log(`Examen du dinosaure : ${nextDino}`); // "T-Rex"
7console.log("File restante :", dinoQueue); // ["Velociraptor", "Triceratops", "Stegosaurus"]
8
9// Traitement du dinosaure suivant
10const anotherDino = dinoQueue.shift();
11console.log(`Dinosaure suivant à examiner : ${anotherDino}`); // "Velociraptor"
12console.log("État actuel de la file :", dinoQueue); // ["Triceratops", "Stegosaurus"]

Quand utiliser shift() :

  • Quand tu dois retirer et récupérer le premier élément d'un tableau
  • Quand tu implémentes des files d'attente (FIFO - First In, First Out)
  • Quand tu traites les éléments dans l'ordre où ils ont été ajoutés

5. splice() - Modifier des éléments à n'importe quelle position

La méthode splice() modifie le contenu d'un tableau en retirant, remplaçant ou ajoutant des éléments. Elle est extrêmement polyvalente car elle permet de modifier le tableau à n'importe quelle position.

Syntaxe de base : array.splice(startIndex, deleteCount, item1, item2, ...) :

  • startIndex : l'index à partir duquel commencer la modification
  • deleteCount : le nombre d'éléments à retirer
  • item1, item2, ... : (optionnel) les éléments à ajouter

5.1. Retirer des éléments avec splice()

1// Liste des espèces de dinosaures dans le parc
2const dinosaurs = ["T-Rex", "Velociraptor", "Triceratops", "Stegosaurus", "Brachiosaurus"];
3
4// Retire 2 éléments à partir de l'index 1 (le deuxième élément)
5const removedDinos = dinosaurs.splice(1, 2);
6console.log("Dinosaures retirés :", removedDinos); // ["Velociraptor", "Triceratops"]
7console.log("Dinosaures restants :", dinosaurs); // ["T-Rex", "Stegosaurus", "Brachiosaurus"]

5.2. Remplacer des éléments avec splice()

1// Liste des espèces de dinosaures
2const dinosaurs = ["T-Rex", "Dilophosaurus", "Triceratops", "Stegosaurus"];
3
4// Remplace Dilophosaurus par Velociraptor
5const replaced = dinosaurs.splice(1, 1, "Velociraptor");
6console.log("Dinosaure remplacé :", replaced); // ["Dilophosaurus"]
7console.log("Liste actuelle :", dinosaurs); // ["T-Rex", "Velociraptor", "Triceratops", "Stegosaurus"]
8
9// Remplace plusieurs éléments à la fois
10dinosaurs.splice(2, 2, "Brachiosaurus", "Ankylosaurus", "Parasaurolophus");
11console.log("Nouvelle composition :", dinosaurs);
12// ["T-Rex", "Velociraptor", "Brachiosaurus", "Ankylosaurus", "Parasaurolophus"]

5.3. Ajouter des éléments sans en retirer

1// Liste des espèces de dinosaures
2const dinosaurs = ["T-Rex", "Velociraptor"];
3
4// Ajoute une nouvelle espèce à l'index 1 (entre T-Rex et Velociraptor)
5dinosaurs.splice(1, 0, "Dilophosaurus", "Compsognathus");
6console.log(dinosaurs); // ["T-Rex", "Dilophosaurus", "Compsognathus", "Velociraptor"]

Quand utiliser splice() :

  • Quand tu dois modifier un tableau à une position précise, pas seulement à la fin ou au début
  • Quand tu dois retirer et/ou ajouter des éléments simultanément
  • Quand tu veux remplacer une section d'un tableau par de nouvelles valeurs

6. sort() - Trier un tableau

La méthode sort() trie les éléments d'un tableau sur place et renvoie le tableau trié :

1// Liste des dinosaures pour le repas
2const feedingList = ["Velociraptor", "T-Rex", "Dilophosaurus", "Gallimimus", "Compsognathus"];
3
4// Tri alphabétique
5feedingList.sort();
6console.log("Liste de nourrissage (ordre alphabétique) :", feedingList);
7// ["Compsognathus", "Dilophosaurus", "Gallimimus", "T-Rex", "Velociraptor"]
8
9// Tableau avec les tailles des dinosaures (en cm)
10const dinoSizes = [1200, 300, 800, 2000, 40];
11
12// Le tri par défaut traite les nombres comme des chaînes de caractères - ça ne fonctionnera pas correctement !
13dinoSizes.sort();
14console.log("Tailles mal triées :", dinoSizes);
15// Probablement : [1200, 2000, 300, 40, 800] - incorrect !
16
17// Tri numérique correct avec une fonction de comparaison
18dinoSizes.sort((a, b) => a - b);
19console.log("Tailles correctement triées (ordre croissant) :", dinoSizes);
20// [40, 300, 800, 1200, 2000]
21
22// Tri décroissant
23dinoSizes.sort((a, b) => b - a);
24console.log("Tailles triées par ordre décroissant :", dinoSizes);
25// [2000, 1200, 800, 300, 40]

Trier des objets

1// Données des dinosaures pour le repas
2const dinosaurs = [
3  { name: "T-Rex", weight: 7000, priority: 1 },
4  { name: "Velociraptor", weight: 100, priority: 2 },
5  { name: "Triceratops", weight: 9000, priority: 3 },
6  { name: "Gallimimus", weight: 450, priority: 4 }
7];
8
9// Tri par priorité de repas
10dinosaurs.sort((a, b) => a.priority - b.priority);
11console.log("Ordre des repas par priorité :");
12dinosaurs.forEach(dino => console.log(`${dino.name} (priorité : ${dino.priority})`));
13
14// Tri par poids (le plus lourd en premier)
15dinosaurs.sort((a, b) => b.weight - a.weight);
16console.log("\nOrdre par poids (le plus lourd en premier) :");
17dinosaurs.forEach(dino => console.log(`${dino.name} (${dino.weight} kg)`));
18
19// Tri alphabétique par nom
20dinosaurs.sort((a, b) => a.name.localeCompare(b.name));
21console.log("\nDinosaures par ordre alphabétique :");
22dinosaurs.forEach(dino => console.log(`${dino.name}`));

La méthode sort() accepte une fonction de comparaison optionnelle qui doit renvoyer :

  • Une valeur négative si a doit être placé avant b
  • Zéro si a et b sont équivalents du point de vue du tri
  • Une valeur positive si a doit être placé après b

Quand utiliser sort() :

  • Quand tu dois ordonner les éléments d'un tableau selon un critère précis
  • Quand tu travailles avec des listes qui doivent être présentées dans un ordre spécifique
  • Quand tu implémentes une fonctionnalité de tri dans une application

7. reverse() - Inverser l'ordre d'un tableau

La méthode reverse() inverse l'ordre des éléments d'un tableau et renvoie le tableau inversé :

1// Liste des dinosaures du plus vieux au plus jeune
2const dinosaursByAge = ["Brachiosaurus", "Stegosaurus", "Triceratops", "Velociraptor", "T-Rex"];
3
4// Inverse l'ordre pour aller du plus jeune au plus vieux
5dinosaursByAge.reverse();
6console.log("Du plus jeune au plus vieux :", dinosaursByAge);
7// ["T-Rex", "Velociraptor", "Triceratops", "Stegosaurus", "Brachiosaurus"]
8
9// Souvent utilisé en combinaison avec sort()
10const dinoHeights = [500, 900, 200, 1200, 350];
11// Tri décroissant en triant par ordre croissant puis en inversant
12dinoHeights.sort((a, b) => a - b).reverse();
13console.log("Hauteurs par ordre décroissant :", dinoHeights);
14// [1200, 900, 500, 350, 200]

Quand utiliser reverse() :

  • Quand tu dois inverser l'ordre des éléments d'un tableau
  • Quand tu veux passer d'un ordre croissant à décroissant (ou l'inverse) après un tri
  • Quand tu implémentes une fonctionnalité d'« ordre inversé » dans une interface utilisateur

8. fill() - Remplir un tableau avec une valeur

La méthode fill() remplit tous les éléments d'un tableau, d'un index de départ à un index de fin (exclu), avec une valeur spécifiée :

1// Préparation d'un tableau pour les relevés de température des dinosaures (10 relevés)
2const temperatures = new Array(10);
3
4// Remplissage avec une valeur par défaut (38.5 degrés Celsius)
5temperatures.fill(38.5);
6console.log("Températures par défaut :", temperatures);
7// [38.5, 38.5, 38.5, 38.5, 38.5, 38.5, 38.5, 38.5, 38.5, 38.5]
8
9// Remplit seulement une partie du tableau
10temperatures.fill(39.2, 2, 5); // De l'index 2 (inclus) à 5 (exclu)
11console.log("Températures mises à jour :", temperatures);
12// [38.5, 38.5, 39.2, 39.2, 39.2, 38.5, 38.5, 38.5, 38.5, 38.5]
13
14// Utilisation avec un nouveau tableau et des index négatifs (comptés depuis la fin)
15const feedingSchedule = new Array(7).fill("Standard");
16feedingSchedule.fill("Portion supplémentaire", -3); // Les 3 derniers jours
17console.log("Plan de nourrissage de la semaine :", feedingSchedule);
18// ["Standard", "Standard", "Standard", "Standard", "Portion supplémentaire", "Portion supplémentaire", "Portion supplémentaire"]

Quand utiliser fill() :

  • Quand tu crées un nouveau tableau et dois le remplir avec une valeur initiale précise
  • Quand tu dois remplacer tout ou partie des valeurs d'un tableau existant
  • Quand tu initialises des tableaux pour stocker des données avec des valeurs par défaut

Application pratique des méthodes de base des tableaux

Maintenant, combinons les méthodes que nous avons apprises pour résoudre des scénarios plus pratiques dans notre Jurassic Park :

Exemple 1 : Système de gestion de la nourriture des dinosaures

1// Système de gestion de la nourriture des dinosaures
2const feedingSystem = {
3  // État du système
4  foodInventory: [],
5  feedingQueue: [],
6  feedingHistory: [],
7
8  // Ajout d'un nouvel approvisionnement
9  addFoodSupply: function(type, quantity, expirationDate) {
10    const supply = { type, quantity, expirationDate, addedOn: new Date() };
11    this.foodInventory.push(supply);
12
13    // Trie par date d'expiration (la plus proche en premier)
14    this.foodInventory.sort((a, b) =>
15      new Date(a.expirationDate) - new Date(b.expirationDate)
16    );
17
18    console.log(`Ajout de ${quantity}kg de nourriture "${type}" aux réserves.`);
19    return supply;
20  },
21
22  // Ajout d'un dinosaure à la file d'attente de repas
23  scheduleDinoFeeding: function(dinoId, dinoName, foodType, quantity, priority) {
24    const feedingRequest = {
25      dinoId,
26      dinoName,
27      foodType,
28      quantity,
29      priority,
30      scheduledAt: new Date()
31    };
32
33    if (priority === "high") {
34      // Ajoute en tête de file
35      this.feedingQueue.unshift(feedingRequest);
36    } else {
37      // Ajoute en fin de file
38      this.feedingQueue.push(feedingRequest);
39    }
40
41    console.log(`Repas planifié pour ${dinoName} (priorité : ${priority})`);
42    return this.feedingQueue.length;
43  },
44
45  // Récupération du prochain dinosaure à nourrir
46  getNextDinoToFeed: function() {
47    if (this.feedingQueue.length === 0) {
48      console.log("Tous les dinosaures sont nourris. File vide.");
49      return null;
50    }
51
52    const nextFeeding = this.feedingQueue.shift();
53    console.log(`Prochain à nourrir : ${nextFeeding.dinoName}`);
54    return nextFeeding;
55  },
56
57  // Distribution de la nourriture depuis l'entrepôt
58  dispenseFoodForDino: function(dinoFeeding) {
59    const { foodType, quantity, dinoName } = dinoFeeding;
60
61    // Recherche de l'approvisionnement adapté
62    let remainingQuantity = quantity;
63    const usedSupplies = [];
64
65    // Parcourt à partir de l'approvisionnement le plus ancien (expire le plus tôt)
66    for (let i = 0; i < this.foodInventory.length && remainingQuantity > 0; i++) {
67      const supply = this.foodInventory[i];
68
69      if (supply.type === foodType && supply.quantity > 0) {
70        // La quantité qu'on peut prendre de cet approvisionnement
71        const amountToTake = Math.min(remainingQuantity, supply.quantity);
72        supply.quantity -= amountToTake;
73        remainingQuantity -= amountToTake;
74
75        usedSupplies.push({
76          type: supply.type,
77          amount: amountToTake,
78          expirationDate: supply.expirationDate
79        });
80
81        // Si l'approvisionnement est vide, on le retire de l'inventaire
82        if (supply.quantity === 0) {
83          this.foodInventory.splice(i, 1);
84          i--; // Ajuste l'index après la suppression de l'élément
85        }
86      }
87    }
88
89    // Ajoute un enregistrement à l'historique des repas
90    const feedingRecord = {
91      ...dinoFeeding,
92      fedAt: new Date(),
93      suppliesUsed: usedSupplies,
94      fullyFed: remainingQuantity === 0
95    };
96
97    this.feedingHistory.push(feedingRecord);
98
99    if (remainingQuantity > 0) {
100      console.log(`ATTENTION : il manque ${remainingQuantity}kg de nourriture "${foodType}" pour ${dinoName} !`);
101      return false;
102    }
103
104    console.log(`${dinoName} a été nourri avec ${quantity}kg de nourriture "${foodType}".`);
105    return feedingRecord;
106  },
107
108  // Exécution d'un cycle complet de repas
109  processFeedingCycle: function(maxFeedings = 5) {
110    console.log("=== DÉBUT DU CYCLE DE REPAS ===");
111    let feedingsProcessed = 0;
112
113    // Traite un nombre défini de repas ou jusqu'à ce que la file soit vide
114    while (feedingsProcessed < maxFeedings && this.feedingQueue.length > 0) {
115      const nextDino = this.getNextDinoToFeed();
116
117      if (nextDino) {
118        const result = this.dispenseFoodForDino(nextDino);
119
120        if (!result) {
121          // Si le repas a échoué, déplace le dinosaure à la fin de la file
122          this.feedingQueue.push({
123            ...nextDino,
124            priority: "high", // Augmente la priorité pour le dinosaure non nourri
125            scheduledAt: new Date()
126          });
127          console.log(`${nextDino.dinoName} déplacé en fin de file avec une priorité haute.`);
128        }
129
130        feedingsProcessed++;
131      }
132    }
133
134    console.log(`=== FIN DU CYCLE DE REPAS (traités : ${feedingsProcessed}) ===`);
135    console.log(`Il reste ${this.feedingQueue.length} dinosaures dans la file`);
136    return feedingsProcessed;
137  },
138
139  // Rapport de l'état de l'inventaire
140  reportInventoryStatus: function() {
141    console.log("=== RAPPORT SUR L'ÉTAT DES STOCKS ===");
142
143    if (this.foodInventory.length === 0) {
144      console.log("L'entrepôt est vide ! Commande de nouvelles réserves de nourriture !");
145      return { isEmpty: true, totalQuantity: 0, types: [] };
146    }
147
148    // Regroupe les approvisionnements par type
149    const inventory = this.foodInventory.reduce((acc, supply) => {
150      if (!acc[supply.type]) {
151        acc[supply.type] = 0;
152      }
153      acc[supply.type] += supply.quantity;
154      return acc;
155    }, {});
156
157    // Calcule la quantité totale
158    const totalQuantity = Object.values(inventory).reduce((sum, qty) => sum + qty, 0);
159
160    console.log(`Réserve totale de nourriture : ${totalQuantity}kg`);
161    Object.entries(inventory).forEach(([type, qty]) => {
162      console.log(`- ${type}: ${qty}kg`);
163    });
164
165    // Vérifie les approvisionnements qui expirent bientôt (dans les 3 jours)
166    const today = new Date();
167    const threeDaysLater = new Date(today);
168    threeDaysLater.setDate(today.getDate() + 3);
169
170    const expiringSupplies = this.foodInventory.filter(supply =>
171      new Date(supply.expirationDate) <= threeDaysLater
172    );
173
174    if (expiringSupplies.length > 0) {
175      console.log("\nRéserves qui expirent dans les 3 jours :");
176      expiringSupplies.forEach(supply => {
177        console.log(`- ${supply.quantity}kg ${supply.type} (expiration : ${supply.expirationDate})`);
178      });
179    }
180
181    return {
182      isEmpty: false,
183      totalQuantity,
184      types: Object.keys(inventory),
185      inventory,
186      expiringSupplies
187    };
188  }
189};
190
191// Démonstration du système
192console.log("=== DÉMONSTRATION DU SYSTÈME DE GESTION DE LA NOURRITURE ===");
193
194// 1. Ajout d'approvisionnements
195feedingSystem.addFoodSupply("Viande", 500, "2023-07-15");
196feedingSystem.addFoodSupply("Plantes", 800, "2023-07-10");
197feedingSystem.addFoodSupply("Poisson", 200, "2023-07-05");
198feedingSystem.addFoodSupply("Viande", 300, "2023-07-20");
199
200// 2. Planification des repas
201feedingSystem.scheduleDinoFeeding("TRX-01", "Rex", "Viande", 150, "high");
202feedingSystem.scheduleDinoFeeding("VEL-02", "Blue", "Viande", 50, "normal");
203feedingSystem.scheduleDinoFeeding("TRCP-03", "Trixie", "Plantes", 120, "normal");
204feedingSystem.scheduleDinoFeeding("BRCH-04", "Bronty", "Plantes", 250, "normal");
205feedingSystem.scheduleDinoFeeding("STEG-05", "Spike", "Plantes", 100, "high");
206
207// 3. Rapport de l'état de l'inventaire avant le repas
208feedingSystem.reportInventoryStatus();
209
210// 4. Traitement du cycle de repas
211feedingSystem.processFeedingCycle(3); // Traite seulement 3 repas
212
213// 5. Vérification de l'état de l'inventaire après le repas
214feedingSystem.reportInventoryStatus();
215
216// 6. Terminer le cycle de repas
217feedingSystem.processFeedingCycle(5); // Traite les repas restants
218
219// 7. Vérification de l'état de l'inventaire après le cycle complet
220feedingSystem.reportInventoryStatus();

Exemple 2 : Gestion des équipes du personnel du parc

1// Système de gestion des équipes du personnel de Jurassic Park
2const staffManagementSystem = {
3  // Données du système
4  departments: [
5    { id: "OPS", name: "Opérations" },
6    { id: "SCI", name: "Recherche scientifique" },
7    { id: "SEC", name: "Sécurité" },
8    { id: "VET", name: "Service vétérinaire" },
9    { id: "MAINT", name: "Maintenance" }
10  ],
11  staff: [],
12  teams: [],
13
14  // Ajout d'un nouvel employé
15  addStaffMember: function(name, role, skills, departmentId) {
16    // Vérifie si le département existe
17    const department = this.departments.find(dept => dept.id === departmentId);
18    if (!department) {
19      console.log(`Erreur : le département avec l'ID "${departmentId}" n'existe pas.`);
20      return null;
21    }
22
23    // Génère l'ID de l'employé
24    const id = `${departmentId}-${(this.staff.length + 1).toString().padStart(3, '0')}`;
25
26    const staffMember = {
27      id,
28      name,
29      role,
30      skills: Array.isArray(skills) ? skills : [skills],
31      departmentId,
32      departmentName: department.name,
33      hireDate: new Date().toISOString().split('T')[0]
34    };
35
36    this.staff.push(staffMember);
37    console.log(`Employé ajouté : ${name} (${role}) au département ${department.name}`);
38
39    return staffMember;
40  },
41
42  // Création d'une nouvelle équipe
43  createTeam: function(name, mission, leaderId) {
44    // Vérifie si le leader existe
45    const leader = this.staff.find(person => person.id === leaderId);
46    if (!leader) {
47      console.log(`Erreur : l'employé avec l'ID "${leaderId}" n'existe pas.`);
48      return null;
49    }
50
51    const teamId = `TEAM-${(this.teams.length + 1).toString().padStart(3, '0')}`;
52
53    const team = {
54      id: teamId,
55      name,
56      mission,
57      createdAt: new Date().toISOString().split('T')[0],
58      leaderId,
59      leaderName: leader.name,
60      members: [leaderId],
61      status: "active"
62    };
63
64    this.teams.push(team);
65    console.log(`Équipe créée : ${name} (mission : ${mission}), leader : ${leader.name}`);
66
67    return team;
68  },
69
70  // Ajout d'un employé à une équipe
71  addMemberToTeam: function(teamId, memberId) {
72    // Recherche l'équipe
73    const teamIndex = this.teams.findIndex(team => team.id === teamId);
74    if (teamIndex === -1) {
75      console.log(`Erreur : l'équipe avec l'ID "${teamId}" n'existe pas.`);
76      return false;
77    }
78
79    // Recherche l'employé
80    const member = this.staff.find(person => person.id === memberId);
81    if (!member) {
82      console.log(`Erreur : l'employé avec l'ID "${memberId}" n'existe pas.`);
83      return false;
84    }
85
86    // Vérifie si l'employé est déjà dans l'équipe
87    if (this.teams[teamIndex].members.includes(memberId)) {
88      console.log(`${member.name} fait déjà partie de l'équipe ${this.teams[teamIndex].name}.`);
89      return false;
90    }
91
92    // Ajoute l'employé à l'équipe
93    this.teams[teamIndex].members.push(memberId);
94    console.log(`Ajout de ${member.name} à l'équipe ${this.teams[teamIndex].name}.`);
95
96    return true;
97  },
98
99  // Suppression d'un employé d'une équipe
100  removeMemberFromTeam: function(teamId, memberId) {
101    // Recherche l'équipe
102    const teamIndex = this.teams.findIndex(team => team.id === teamId);
103    if (teamIndex === -1) {
104      console.log(`Erreur : l'équipe avec l'ID "${teamId}" n'existe pas.`);
105      return false;
106    }
107
108    // Vérifie si l'employé est le leader
109    if (this.teams[teamIndex].leaderId === memberId) {
110      console.log(`Erreur : impossible de retirer le leader de l'équipe. Change d'abord le leader.`);
111      return false;
112    }
113
114    // Recherche l'index de l'employé dans l'équipe
115    const memberIndex = this.teams[teamIndex].members.indexOf(memberId);
116    if (memberIndex === -1) {
117      console.log(`L'employé ne fait pas partie de l'équipe ${this.teams[teamIndex].name}.`);
118      return false;
119    }
120
121    // Recherche l'employé à titre informatif
122    const member = this.staff.find(person => person.id === memberId);
123
124    // Retire l'employé de l'équipe
125    this.teams[teamIndex].members.splice(memberIndex, 1);
126    console.log(`Retrait de ${member ? member.name : memberId} de l'équipe ${this.teams[teamIndex].name}.`);
127
128    return true;
129  },
130
131  // Changement du leader de l'équipe
132  changeTeamLeader: function(teamId, newLeaderId) {
133    // Recherche l'équipe
134    const teamIndex = this.teams.findIndex(team => team.id === teamId);
135    if (teamIndex === -1) {
136      console.log(`Erreur : l'équipe avec l'ID "${teamId}" n'existe pas.`);
137      return false;
138    }
139
140    // Vérifie si le nouveau leader existe
141    const newLeader = this.staff.find(person => person.id === newLeaderId);
142    if (!newLeader) {
143      console.log(`Erreur : l'employé avec l'ID "${newLeaderId}" n'existe pas.`);
144      return false;
145    }
146
147    // Vérifie si le nouveau leader est membre de l'équipe
148    if (!this.teams[teamIndex].members.includes(newLeaderId)) {
149      // Ajoute le nouveau leader à l'équipe s'il n'en est pas déjà membre
150      this.teams[teamIndex].members.push(newLeaderId);
151      console.log(`${newLeader.name} a été ajouté à l'équipe comme nouveau leader.`);
152    }
153
154    // Sauvegarde les infos de l'ancien leader pour le message
155    const oldLeaderId = this.teams[teamIndex].leaderId;
156    const oldLeader = this.staff.find(person => person.id === oldLeaderId);
157
158    // Met à jour le leader
159    this.teams[teamIndex].leaderId = newLeaderId;
160    this.teams[teamIndex].leaderName = newLeader.name;
161
162    console.log(`Le leader de l'équipe ${this.teams[teamIndex].name} passe de ${oldLeader.name} à ${newLeader.name}.`);
163    return true;
164  },
165
166  // Désactivation d'une équipe
167  deactivateTeam: function(teamId, reason) {
168    // Recherche l'équipe
169    const teamIndex = this.teams.findIndex(team => team.id === teamId);
170    if (teamIndex === -1) {
171      console.log(`Erreur : l'équipe avec l'ID "${teamId}" n'existe pas.`);
172      return false;
173    }
174
175    // Sauvegarde l'état avant modification
176    const teamName = this.teams[teamIndex].name;
177
178    // Met à jour le statut de l'équipe
179    this.teams[teamIndex].status = "inactive";
180    this.teams[teamIndex].deactivatedAt = new Date().toISOString().split('T')[0];
181    this.teams[teamIndex].deactivationReason = reason || "Non précisée";
182
183    console.log(`L'équipe ${teamName} a été désactivée. Raison : ${this.teams[teamIndex].deactivationReason}`);
184    return true;
185  },
186
187  // Génération d'un rapport des équipes
188  generateTeamsReport: function(includeInactive = false) {
189    console.log("=== RAPPORT DES ÉQUIPES DE JURASSIC PARK ===");
190
191    // Filtre les équipes par statut si les inactives ne sont pas incluses
192    const teamsToReport = includeInactive
193      ? this.teams
194      : this.teams.filter(team => team.status === "active");
195
196    if (teamsToReport.length === 0) {
197      console.log("Aucune équipe à afficher.");
198      return { teams: [] };
199    }
200
201    // Prépare les données du rapport
202    const teamsData = teamsToReport.map(team => {
203      // Récupère les informations complètes des membres
204      const memberDetails = team.members.map(memberId => {
205        const member = this.staff.find(person => person.id === memberId);
206        return member ? {
207          id: member.id,
208          name: member.name,
209          role: member.role,
210          isLeader: memberId === team.leaderId
211        } : { id: memberId, name: "Inconnu", role: "Inconnu", isLeader: false };
212      });
213
214      return {
215        id: team.id,
216        name: team.name,
217        mission: team.mission,
218        status: team.status,
219        memberCount: team.members.length,
220        leader: this.staff.find(person => person.id === team.leaderId),
221        members: memberDetails,
222        createdAt: team.createdAt,
223        deactivatedAt: team.deactivatedAt,
224        deactivationReason: team.deactivationReason
225      };
226    });
227
228    // Trie les équipes - actives d'abord, puis par date de création
229    teamsData.sort((a, b) => {
230      if (a.status !== b.status) {
231        return a.status === "active" ? -1 : 1;
232      }
233      return new Date(b.createdAt) - new Date(a.createdAt);
234    });
235
236    // Affiche le résumé
237    console.log(`Nombre d'équipes : ${teamsData.length}`);
238    console.log(`Équipes actives : ${teamsData.filter(t => t.status === "active").length}`);
239    if (includeInactive) {
240      console.log(`Équipes inactives : ${teamsData.filter(t => t.status === "inactive").length}`);
241    }
242
243    // Affiche les détails de chaque équipe
244    teamsData.forEach(team => {
245      console.log(`\n${team.id}: ${team.name} (Statut : ${team.status})`);
246      console.log(`Mission : ${team.mission}`);
247      console.log(`Leader : ${team.leader ? team.leader.name : 'Aucun'} (${team.leader ? team.leader.role : ''})`);
248      console.log(`Nombre de membres : ${team.memberCount}`);
249      console.log("Membres :");
250      team.members.forEach(member => {
251        console.log(`  - ${member.name} (${member.role})${member.isLeader ? ' [LEADER]' : ''}`);
252      });
253
254      if (team.status === "inactive") {
255        console.log(`Date de désactivation : ${team.deactivatedAt}`);
256        console.log(`Raison : ${team.deactivationReason}`);
257      }
258    });
259
260    return { teams: teamsData };
261  },
262
263  // Réorganisation des équipes
264  reorganizeTeams: function(fromTeamId, toTeamId, memberIds, dissolveSourceTeam = false) {
265    // Vérifie si les équipes existent
266    const fromTeamIndex = this.teams.findIndex(team => team.id === fromTeamId);
267    const toTeamIndex = this.teams.findIndex(team => team.id === toTeamId);
268
269    if (fromTeamIndex === -1 || toTeamIndex === -1) {
270      console.log(`Erreur : l'une des équipes ou les deux n'existent pas.`);
271      return false;
272    }
273
274    // Vérifie si les équipes sont actives
275    if (this.teams[fromTeamIndex].status !== "active" || this.teams[toTeamIndex].status !== "active") {
276      console.log(`Erreur : les équipes doivent être actives pour être réorganisées.`);
277      return false;
278    }
279
280    // Si aucun membre spécifique n'est indiqué, transfère tout le monde (sauf le leader)
281    const membersToMove = memberIds ||
282      this.teams[fromTeamIndex].members.filter(id => id !== this.teams[fromTeamIndex].leaderId);
283
284    // Transfère les membres
285    for (const memberId of membersToMove) {
286      // Vérifie si l'employé fait partie de l'équipe source
287      if (!this.teams[fromTeamIndex].members.includes(memberId)) {
288        console.log(`Erreur : l'employé avec l'ID ${memberId} ne fait pas partie de l'équipe source.`);
289        continue;
290      }
291
292      // Vérifie si l'employé est le leader (si on ne veut pas tous les transférer)
293      if (memberIds && memberId === this.teams[fromTeamIndex].leaderId) {
294        console.log(`Impossible de transférer le leader de l'équipe. Change d'abord le leader.`);
295        continue;
296      }
297
298      // Vérifie si l'employé fait déjà partie de l'équipe cible
299      if (this.teams[toTeamIndex].members.includes(memberId)) {
300        console.log(`L'employé avec l'ID ${memberId} fait déjà partie de l'équipe cible.`);
301        continue;
302      }
303
304      // Retire de l'équipe d'origine
305      const fromIndex = this.teams[fromTeamIndex].members.indexOf(memberId);
306      this.teams[fromTeamIndex].members.splice(fromIndex, 1);
307
308      // Ajoute à la nouvelle équipe
309      this.teams[toTeamIndex].members.push(memberId);
310
311      // Recherche le nom de l'employé pour les journaux
312      const member = this.staff.find(person => person.id === memberId);
313      console.log(`Transfert de ${member ? member.name : memberId} de l'équipe ${this.teams[fromTeamIndex].name} vers ${this.teams[toTeamIndex].name}`);
314    }
315
316    // Si on choisit de dissoudre l'équipe source et qu'il ne reste plus de membres
317    if (dissolveSourceTeam || this.teams[fromTeamIndex].members.length === 0) {
318      this.deactivateTeam(fromTeamId, "Réorganisation - équipe transférée");
319    }
320
321    return true;
322  }
323};
324
325// Démonstration du système de gestion des équipes du personnel
326console.log("=== DÉMONSTRATION DU SYSTÈME DE GESTION DES ÉQUIPES DU PERSONNEL ===");
327
328// 1. Ajout des employés
329const owen = staffManagementSystem.addStaffMember("Owen Grady", "Dresseur de dinosaures", ["Comportement animal", "Dressage", "Premiers secours"], "OPS");
330const claire = staffManagementSystem.addStaffMember("Claire Dearing", "Directrice des opérations", ["Gestion", "Marketing", "Administration"], "OPS");
331const dr_wu = staffManagementSystem.addStaffMember("Dr. Henry Wu", "Généticien en chef", ["Génétique", "Bio-ingénierie", "Clonage"], "SCI");
332const barry = staffManagementSystem.addStaffMember("Barry", "Dresseur adjoint", ["Dressage", "Soins aux animaux"], "OPS");
333const lowery = staffManagementSystem.addStaffMember("Lowery Cruthers", "Technicien systèmes", ["Informatique", "Surveillance", "Communication"], "SEC");
334const vivian = staffManagementSystem.addStaffMember("Vivian Krill", "Coordinatrice de la sécurité", ["Sécurité", "Communication", "Gestion de crise"], "SEC");
335const muldoon = staffManagementSystem.addStaffMember("Robert Muldoon", "Spécialiste de la sécurité", ["Armes à feu", "Sécurité", "Pistage"], "SEC");
336const malcolm = staffManagementSystem.addStaffMember("Dr. Ian Malcolm", "Mathématicien", ["Théorie du chaos", "Analyse des risques", "Modélisation"], "SCI");
337const sattler = staffManagementSystem.addStaffMember("Dr. Ellie Sattler", "Paléobotaniste", ["Botanique", "Paléontologie", "Écologie"], "SCI");
338const harding = staffManagementSystem.addStaffMember("Dr. Gerry Harding", "Vétérinaire", ["Médecine vétérinaire", "Zoologie", "Médecine"], "VET");
339
340// 2. Création des équipes
341const raptorTeam = staffManagementSystem.createTeam("Équipe Velociraptor", "Dressage et soins des Velociraptors", owen.id);
342staffManagementSystem.addMemberToTeam(raptorTeam.id, barry.id);
343
344const securityTeam = staffManagementSystem.createTeam("Équipe de sécurité", "Assurer la sécurité du parc", muldoon.id);
345staffManagementSystem.addMemberToTeam(securityTeam.id, vivian.id);
346staffManagementSystem.addMemberToTeam(securityTeam.id, lowery.id);
347
348const scienceTeam = staffManagementSystem.createTeam("Équipe scientifique", "Recherche et développement scientifiques", dr_wu.id);
349staffManagementSystem.addMemberToTeam(scienceTeam.id, malcolm.id);
350staffManagementSystem.addMemberToTeam(scienceTeam.id, sattler.id);
351
352// 3. Rapport des équipes
353staffManagementSystem.generateTeamsReport();
354
355// 4. Réorganisation des équipes
356console.log("\n=== RÉORGANISATION DES ÉQUIPES ===");
357
358// Création d'une nouvelle équipe de gestion de crise
359const crisisTeam = staffManagementSystem.createTeam("Équipe de gestion de crise", "Réagir aux situations de crise", claire.id);
360
361// Transfert de membres depuis d'autres équipes
362staffManagementSystem.reorganizeTeams(securityTeam.id, crisisTeam.id, [vivian.id]);
363staffManagementSystem.addMemberToTeam(crisisTeam.id, malcolm.id); // Ajout de Malcolm comme conseiller en gestion des risques
364staffManagementSystem.addMemberToTeam(crisisTeam.id, harding.id);  // Ajout du vétérinaire
365
366// Changement du leader de l'équipe scientifique
367staffManagementSystem.changeTeamLeader(scienceTeam.id, sattler.id);
368
369// Désactivation d'une équipe
370staffManagementSystem.deactivateTeam(raptorTeam.id, "Projet suspendu - incident avec les raptors");
371
372// 5. Rapport final des équipes (incluant les inactives)
373staffManagementSystem.generateTeamsReport(true);

Récapitulatif

Dans cette leçon, nous avons appris les méthodes de base pour modifier les tableaux en JavaScript :

  1. push() - ajoute des éléments à la fin d'un tableau
  2. pop() - retire et renvoie le dernier élément d'un tableau
  3. unshift() - ajoute des éléments au début d'un tableau
  4. shift() - retire et renvoie le premier élément d'un tableau
  5. splice() - ajoute, retire ou remplace des éléments à n'importe quelle position d'un tableau
  6. sort() - trie les éléments d'un tableau
  7. reverse() - inverse l'ordre des éléments d'un tableau
  8. fill() - remplit les éléments d'un tableau avec une valeur spécifiée

La capacité à utiliser efficacement ces méthodes est cruciale pour travailler avec des données en JavaScript. Elles te permettent de gérer des collections, d'implémenter des structures de données (comme des piles et des files), et de manipuler les données efficacement.

Il est important de se rappeler que les méthodes ci-dessus modifient le tableau original (sauf si tu crées une copie avant de les appliquer). Dans une des prochaines leçons, nous apprendrons les méthodes de tableaux qui ne modifient pas l'original mais renvoient un nouveau tableau ou une nouvelle valeur.

Code de cette leçon : index.js
1// Méthodes des tableaux - Parc Jurassique
2console.log("Laboratoire des Méthodes de Tableaux");
3console.log("Opérations avancées sur les collections\n");
4
5// ===========================================
6// 1. forEach() - ITÉRATION
7// ===========================================
8console.log("=== 1. forEach() - Itération ===");
9
10const dinosaurs = ["T-Rex", "Velociraptor", "Triceratops", "Stegosaurus"];
11
12console.log("\nListe des dinosaures:");
13dinosaurs.forEach((dino, index) => {
14  console.log(`  ${index + 1}. ${dino}`);
15});
16
17// forEach avec tous les paramètres
18console.log("\nVersion complète de forEach:");
19dinosaurs.forEach((element, index, array) => {
20  console.log(`  [${index}] ${element} du tableau de longueur ${array.length}`);
21});
22
23// ===========================================
24// 2. map() - TRANSFORMATION
25// ===========================================
26console.log("\n=== 2. map() - Transformation ===");
27
28const dinoData = [
29  { name: "T-Rex", weight: 8000 },
30  { name: "Velociraptor", weight: 80 },
31  { name: "Triceratops", weight: 9000 }
32];
33
34// Extraction des noms seulement
35const names = dinoData.map(dino => dino.name);
36console.log("\nNoms seulement:", names);
37
38// Transformation vers un nouveau format
39const formatted = dinoData.map(dino => ({
40  species: dino.name,
41  weightInTons: dino.weight / 1000,
42  category: dino.weight > 1000 ? "Grand" : "Petit"
43}));
44
45console.log("\nTransformées:");
46formatted.forEach(d => {
47  console.log(`  ${d.species}: ${d.weightInTons}t - ${d.category}`);
48});
49
50// ===========================================
51// 3. filter() - FILTRAGE
52// ===========================================
53console.log("\n=== 3. filter() - Filtrage ===");
54
55const allDinos = [
56  { name: "T-Rex", weight: 8000, carnivore: true },
57  { name: "Velociraptor", weight: 80, carnivore: true },
58  { name: "Triceratops", weight: 9000, carnivore: false },
59  { name: "Stegosaurus", weight: 5000, carnivore: false },
60  { name: "Brachiosaurus", weight: 50000, carnivore: false }
61];
62
63// Seulement les carnivores
64const carnivores = allDinos.filter(dino => dino.carnivore);
65console.log("\nCarnivores:", carnivores.map(d => d.name));
66
67// Dinosaures lourds (> 5000kg)
68const heavy = allDinos.filter(dino => dino.weight > 5000);
69console.log("Lourds (>5t):", heavy.map(d => d.name));
70
71// Combinaison de conditions
72const heavyCarnivores = allDinos.filter(d => d.carnivore && d.weight > 100);
73console.log("Carnivores lourds:", heavyCarnivores.map(d => d.name));
74
75// ===========================================
76// 4. find() et findIndex()
77// ===========================================
78console.log("\n=== 4. find() et findIndex() ===");
79
80const park = [
81  { id: 1, name: "T-Rex", sector: "A" },
82  { id: 2, name: "Velociraptor", sector: "B" },
83  { id: 3, name: "Triceratops", sector: "C" }
84];
85
86// find() - premier élément qui remplit une condition
87const foundDino = park.find(dino => dino.sector === "B");
88console.log("\nfind(sector === 'B'):", foundDino);
89
90// findIndex() - index du premier élément
91const foundIndex = park.findIndex(dino => dino.name === "Triceratops");
92console.log("findIndex(name === 'Triceratops'):", foundIndex);
93
94// Élément non trouvé
95const notFound = park.find(dino => dino.name === "Pteranodon");
96console.log("find(Pteranodon):", notFound); // undefined
97
98// ===========================================
99// 5. reduce() - AGRÉGATION
100// ===========================================
101console.log("\n=== 5. reduce() - Agrégation ===");
102
103const weights = [
104  { name: "T-Rex", weight: 8000 },
105  { name: "Velociraptor", weight: 80 },
106  { name: "Triceratops", weight: 9000 },
107  { name: "Stegosaurus", weight: 5000 }
108];
109
110// Somme des poids
111const totalWeight = weights.reduce((sum, dino) => sum + dino.weight, 0);
112console.log(`\nPoids total: ${totalWeight}kg`);
113
114// Poids moyen
115const avgWeight = totalWeight / weights.length;
116console.log(`Poids moyen: ${avgWeight.toFixed(2)}kg`);
117
118// Regroupement par poids
119const grouped = weights.reduce((acc, dino) => {
120  const category = dino.weight > 1000 ? "heavy" : "light";
121  if (!acc[category]) acc[category] = [];
122  acc[category].push(dino.name);
123  return acc;
124}, {});
125
126console.log("\nRegroupées:");
127console.log("  Lourds:", grouped.heavy);
128console.log("  Légers:", grouped.light);
129
130// Recherche du maximum
131const heaviest = weights.reduce((max, dino) =>
132  dino.weight > max.weight ? dino : max
133);
134console.log(`\nLe plus lourd: ${heaviest.name} (${heaviest.weight}kg)`);
135
136// ===========================================
137// 6. some() et every()
138// ===========================================
139console.log("\n=== 6. some() et every() ===");
140
141const herd = [
142  { name: "Trike", health: 95 },
143  { name: "Stego", health: 88 },
144  { name: "Brachio", health: 72 }
145];
146
147// some() - au moins un
148const hasSick = herd.some(dino => dino.health < 80);
149console.log("\nY a-t-il des malades (<80%):", hasSick);
150
151const hasHealthy = herd.some(dino => dino.health > 90);
152console.log("Y en a-t-il en très bonne santé (>90%):", hasHealthy);
153
154// every() - tous
155const allHealthy = herd.every(dino => dino.health >= 80);
156console.log("Tous en bonne santé (≥80%):", allHealthy);
157
158const allCritical = herd.every(dino => dino.health < 50);
159console.log("Tous critiques (<50%):", allCritical);
160
161// ===========================================
162// 7. sort() - TRI
163// ===========================================
164console.log("\n=== 7. sort() - Tri ===");
165
166const unsorted = ["Velociraptor", "T-Rex", "Brachiosaurus", "Stegosaurus"];
167
168// Alphabétiquement
169const alphabetical = [...unsorted].sort();
170console.log("\nAlphabétiquement:", alphabetical);
171
172// Ordre alphabétique inverse
173const reverseAlpha = [...unsorted].sort((a, b) => b.localeCompare(a));
174console.log("Inverse:", reverseAlpha);
175
176// Tri d'objets
177const dinoStats = [
178  { name: "T-Rex", health: 85 },
179  { name: "Velociraptor", health: 100 },
180  { name: "Triceratops", health: 70 }
181];
182
183const byHealth = [...dinoStats].sort((a, b) => b.health - a.health);
184console.log("\nPar santé (décroissant):");
185byHealth.forEach(d => console.log(`  ${d.name}: ${d.health}%`));
186
187// ===========================================
188// 8. CHAÎNAGE DE MÉTHODES
189// ===========================================
190console.log("\n=== 8. Chaînage de méthodes ===");
191
192const inventory = [
193  { name: "Rexy", species: "T-Rex", sector: "A", health: 95, carnivore: true },
194  { name: "Blue", species: "Velociraptor", sector: "B", health: 100, carnivore: true },
195  { name: "Charlie", species: "Velociraptor", sector: "B", health: 85, carnivore: true },
196  { name: "Trike", species: "Triceratops", sector: "C", health: 70, carnivore: false },
197  { name: "Stego", species: "Stegosaurus", sector: "C", health: 92, carnivore: false }
198];
199
200// Trouver les carnivores en bonne santé et les trier par nom
201const healthyCarnivores = inventory
202  .filter(d => d.carnivore)
203  .filter(d => d.health >= 90)
204  .map(d => d.name)
205  .sort();
206
207console.log("\nCarnivores en bonne santé (≥90%):", healthyCarnivores);
208
209// Somme de santé des herbivores
210const herbivoreHealth = inventory
211  .filter(d => !d.carnivore)
212  .reduce((sum, d) => sum + d.health, 0);
213
214console.log(`Somme de santé des herbivores: ${herbivoreHealth}%`);
215
216// ===========================================
217// 9. flat() et flatMap()
218// ===========================================
219console.log("\n=== 9. flat() et flatMap() ===");
220
221const sectors = [
222  ["T-Rex", "Spinosaurus"],
223  ["Velociraptor", "Dilophosaurus"],
224  ["Triceratops", "Stegosaurus"]
225];
226
227// flat() - aplatissement d'un tableau imbriqué
228const flatDinos = sectors.flat();
229console.log("\nflat():", flatDinos);
230
231// flatMap() - map + flat en une seule opération
232const withEmoji = sectors.flatMap(sector =>
233  sector.map(dino => `${dino}`)
234);
235console.log("flatMap():", withEmoji);
236
237// ===========================================
238// 10. EXEMPLE COMPLET
239// ===========================================
240console.log("\n=== 10. Système d'analyse - exemple complet ===");
241
242class DinosaurAnalytics {
243  constructor(dinosaurs) {
244    this.dinosaurs = dinosaurs;
245  }
246
247  // Statistiques générales
248  getOverallStats() {
249    const total = this.dinosaurs.length;
250    const avgHealth = this.dinosaurs.reduce((sum, d) => sum + d.health, 0) / total;
251    const carnivoreCount = this.dinosaurs.filter(d => d.carnivore).length;
252
253    return {
254      total,
255      avgHealth: avgHealth.toFixed(1),
256      carnivores: carnivoreCount,
257      herbivores: total - carnivoreCount
258    };
259  }
260
261  // Top N par santé
262  getHealthiest(n = 3) {
263    return this.dinosaurs
264      .sort((a, b) => b.health - a.health)
265      .slice(0, n)
266      .map(d => ({ name: d.name, health: d.health }));
267  }
268
269  // Regroupement par secteur
270  groupBySector() {
271    return this.dinosaurs.reduce((acc, dino) => {
272      if (!acc[dino.sector]) acc[dino.sector] = [];
273      acc[dino.sector].push(dino.name);
274      return acc;
275    }, {});
276  }
277
278  // Alertes pour les malades
279  getHealthAlerts() {
280    return this.dinosaurs
281      .filter(d => d.health < 80)
282      .map(d => ({
283        name: d.name,
284        sector: d.sector,
285        health: d.health,
286        priority: d.health < 50 ? "CRITIQUE" : "ATTENTION"
287      }))
288      .sort((a, b) => a.health - b.health);
289  }
290
291  // Rapport du secteur
292  getSectorReport(sector) {
293    const dinosInSector = this.dinosaurs.filter(d => d.sector === sector);
294
295    if (dinosInSector.length === 0) {
296      return { error: `Aucun dinosaure dans le secteur ${sector}` };
297    }
298
299    const avgHealth = dinosInSector.reduce((sum, d) => sum + d.health, 0) / dinosInSector.length;
300    const carnivores = dinosInSector.filter(d => d.carnivore);
301    const herbivores = dinosInSector.filter(d => !d.carnivore);
302
303    return {
304      sector,
305      total: dinosInSector.length,
306      avgHealth: avgHealth.toFixed(1),
307      carnivores: carnivores.map(d => d.name),
308      herbivores: herbivores.map(d => d.name),
309      list: dinosInSector.map(d => `${d.name} (${d.health}%)`)
310    };
311  }
312
313  // Afficher toutes les analyses
314  displayFullReport() {
315    console.log("\nRAPPORT ANALYTIQUE COMPLET");
316    console.log("=".repeat(70));
317
318    // Statistiques générales
319    const stats = this.getOverallStats();
320    console.log("\nStatistiques générales:");
321    console.log(`   Total des dinosaures: ${stats.total}`);
322    console.log(`   Santé moyenne: ${stats.avgHealth}%`);
323    console.log(`   Carnivores: ${stats.carnivores}`);
324    console.log(`   Herbivores: ${stats.herbivores}`);
325
326    // Les plus en bonne santé
327    const healthiest = this.getHealthiest(3);
328    console.log("\nTOP 3 - Les plus en bonne santé:");
329    healthiest.forEach((d, i) => {
330      console.log(`   ${i + 1}. ${d.name} - ${d.health}%`);
331    });
332
333    // Répartition par secteurs
334    const sectors = this.groupBySector();
335    console.log("\nRépartition par secteurs:");
336    Object.entries(sectors).sort().forEach(([sector, dinos]) => {
337      console.log(`   Secteur ${sector}: ${dinos.join(", ")}`);
338    });
339
340    // Alertes de santé
341    const alerts = this.getHealthAlerts();
342    if (alerts.length > 0) {
343      console.log("\nALERTES DE SANTÉ:");
344      alerts.forEach(alert => {
345        console.log(`   [${alert.priority}] ${alert.name} - Secteur ${alert.sector} - ${alert.health}%`);
346      });
347    } else {
348      console.log("\nAucune alerte de santé");
349    }
350
351    // Rapports des secteurs
352    const uniqueSectors = [...new Set(this.dinosaurs.map(d => d.sector))].sort();
353    console.log("\nDÉTAILS DES SECTEURS:");
354    uniqueSectors.forEach(sector => {
355      const report = this.getSectorReport(sector);
356      console.log(`\n   Secteur ${report.sector}:`);
357      console.log(`     Dinosaures: ${report.total}`);
358      console.log(`     Santé moyenne: ${report.avgHealth}%`);
359      if (report.carnivores.length > 0) {
360        console.log(`     Carnivores: ${report.carnivores.join(", ")}`);
361      }
362      if (report.herbivores.length > 0) {
363        console.log(`     Herbivores: ${report.herbivores.join(", ")}`);
364      }
365    });
366  }
367}
368
369// Données de test
370const testData = [
371  { name: "Rexy", species: "T-Rex", sector: "A", health: 95, carnivore: true },
372  { name: "Blue", species: "Velociraptor", sector: "B", health: 100, carnivore: true },
373  { name: "Charlie", species: "Velociraptor", sector: "B", health: 85, carnivore: true },
374  { name: "Delta", species: "Velociraptor", sector: "B", health: 45, carnivore: true },
375  { name: "Trike", species: "Triceratops", sector: "C", health: 70, carnivore: false },
376  { name: "Stego", species: "Stegosaurus", sector: "C", health: 92, carnivore: false },
377  { name: "Brachio", species: "Brachiosaurus", sector: "D", health: 88, carnivore: false }
378];
379
380// Exécuter l'analyse
381const analytics = new DinosaurAnalytics(testData);
382analytics.displayFullReport();
383
384console.log("\nFélicitations ! Tu maîtrises maintenant les méthodes des tableaux !");

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. 1. Que fait la méthode Array.prototype.pop() ?

  2. 2. Que va retourner typeof undefined ?

  3. 3. Quel est le moyen le plus simple de vérifier la valeur d'une variable pendant le débogage ?

  4. 4. Pourquoi utiliser const plutôt que let lorsque la valeur d'une variable ne changera pas ?

Tâches pratiques dans le jeu

  • Éditeur de code

    Crée un tableau species avec les espèces 'T-Rex', 'Velociraptor' et 'Triceratops'. Ajoute 'Stegosaurus' à la fin avec push(), supprime le premier élément avec shift() et enregistre-le dans une constante removed. Affiche dans la console le tableau species et sa longueur (length).

  • Clique dans l'ordre

    Range les éléments d'un littéral de template avec interpolation :

  • Éditeur de code

    Enregistre sous forme de BigInt : const dinoEraStart = 245000000n (le début de l'ère des dinosaures, en années avant aujourd'hui) et const dinoEraEnd = 66000000n (sa fin). Calcule dinoEraDuration comme la différence dinoEraStart - dinoEraEnd, et dinoEraDays comme dinoEraDuration multiplié par 365n. Affiche les deux résultats dans la console.

  • Tri horizontal

    Range les éléments permettant de vérifier le type d'une variable :

  • Éditeur de code

    Crée une constante species contenant le nom d'une espèce de dinosaure sous forme de texte, par exemple 'Tyrannosaurus Rex', et une variable age (let) avec l'âge 25. Après l'anniversaire, change age en 26 et affiche species et age dans la console.

  • Tri vertical

    Range les endroits où JavaScript recherche une variable (chaîne de portée) :

  • Tri horizontal

    Range les éléments d'une déclaration de fonction fléchée :

  • Éditeur de code

    Écris une fonction ageInMillions(years) qui renvoie l'âge d'un fossile en millions d'années, arrondi à un nombre entier avec Math.round(). Appelle-la pour un fossile vieux de 66000000 ans et affiche le résultat dans la console.

  • Clique dans l'ordre

    Range les étapes du processus d'allocation de mémoire pour les variables :

  • Tri vertical

    Range les étapes de vérification du type d'une variable dans du code de production :

  • Tri vertical

    Range l'introduction des nouveaux types de données JavaScript par ordre chronologique :

  • Clique dans l'ordre

    Range les éléments d'une déclaration de tableau en JavaScript

  • Tri vertical

    Range les étapes de gestion de la mémoire pour les variables en JavaScript :

  • Tri horizontal

    Range les éléments permettant d'ajouter un élément à un tableau :

Articles utiles