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

Créer des objets (littéraux, constructeurs)

12 min de lecture
Dans cette leçon8

À Jurassic Park, nous utilisons les objets JavaScript pour représenter de nombreux éléments de notre écosystème - des dinosaures et de leurs comportements, en passant par les zones du parc, jusqu'aux données du personnel et aux procédures de sécurité. Les objets sont un type de données fondamental en JavaScript, qui permet de créer des structures de données complexes dotées de propriétés et de méthodes.

Les littéraux d'objet

La façon la plus simple de créer des objets en JavaScript consiste à utiliser un littéral d'objet - la notation avec des accolades {}.

1// Un objet dinosaure simple, créé à l'aide d'un littéral d'objet
2const velociraptor = {
3  name: "Blue",
4  species: "Velociraptor",
5  age: 4,
6  length: 2.1, // mètres
7  weight: 80, // kilogrammes
8  maxSpeed: 64, // km/h
9  diet: "carnivore",
10  location: "Secteur B",
11  dangerous: true
12};
13
14console.log(velociraptor.name); // "Blue"
15console.log(velociraptor.species); // "Velociraptor"
16console.log(velociraptor.maxSpeed); // 64

Accéder aux propriétés

Nous pouvons accéder aux propriétés d'un objet de deux façons :

1// Notation pointée
2console.log(velociraptor.diet); // "carnivore"
3
4// Notation entre crochets (utile quand le nom de la propriété est stocké dans une variable)
5const propertyName = "location";
6console.log(velociraptor[propertyName]); // "Secteur B"
7
8// La notation entre crochets est aussi utile quand le nom de la propriété contient des caractères spéciaux ou des espaces
9const dinoDetails = {
10  "full name": "Velociraptor antirrhopus",
11  "security-level": "Alpha"
12};
13
14console.log(dinoDetails["full name"]); // "Velociraptor antirrhopus"
15console.log(dinoDetails["security-level"]); // "Alpha"

Les méthodes d'objet

Les objets peuvent aussi contenir des fonctions, que nous appelons des méthodes :

1const velociraptor = {
2  name: "Blue",
3  species: "Velociraptor",
4  age: 4,
5  hunger: 50, // pourcentage (0-100)
6  health: 100, // pourcentage (0-100)
7
8  // Méthode pour nourrir le dinosaure
9  feed: function() {
10    if (this.hunger <= 0) {
11      return "Blue n'a pas faim.";
12    }
13
14    this.hunger -= 30;
15    if (this.hunger < 0) this.hunger = 0;
16
17    return "Blue a été nourrie. Niveau de faim : " + this.hunger + "%";
18  },
19
20  // Syntaxe de méthode raccourcie (introduite avec ES6)
21  makeSound() {
22    return "Blue pousse un cri aigu et perçant !";
23  },
24
25  // Méthode qui vérifie l'état de santé
26  checkStatus() {
27    return `Dinosaure : ${this.name} (Espèce : ${this.species})
28État de santé : ${this.health}%
29Niveau de faim : ${this.hunger}%
30État général : ${this.health > 80 ? "Excellent" : this.health > 50 ? "Bon" : "Nécessite des soins vétérinaires"}`;
31  }
32};
33
34console.log(velociraptor.makeSound()); // "Blue pousse un cri aigu et perçant !"
35console.log(velociraptor.feed()); // "Blue a été nourrie. Niveau de faim : 20%"
36console.log(velociraptor.checkStatus());

Dans les méthodes, le mot-clé this fait référence à l'objet sur lequel la méthode est appelée.

Ajouter et supprimer des propriétés dynamiquement

Nous pouvons ajouter et supprimer dynamiquement des propriétés des objets JavaScript :

1const triceratops = {
2  name: "Trixie",
3  species: "Triceratops",
4  age: 6
5};
6
7// Ajout de nouvelles propriétés
8triceratops.health = 95;
9triceratops["location"] = "Secteur C";
10
11// Ajout d'une méthode
12triceratops.updateHealth = function(amount) {
13  this.health += amount;
14  if (this.health > 100) this.health = 100;
15  if (this.health < 0) this.health = 0;
16  return `Santé de ${this.name} mise à jour à ${this.health}%`;
17};
18
19console.log(triceratops.updateHealth(-15)); // "Santé de Trixie mise à jour à 80%"
20
21// Suppression d'une propriété
22delete triceratops.age;
23console.log(triceratops.age); // undefined

Les constructeurs et l'opérateur new

Quand nous devons créer de nombreux objets similaires, une approche plus efficace consiste à utiliser une fonction constructeur et l'opérateur new.

1// Fonction constructeur pour les dinosaures
2function Dinosaur(name, species, age, diet) {
3  this.name = name;
4  this.species = species;
5  this.age = age;
6  this.diet = diet;
7  this.health = 100;
8  this.hunger = 50;
9
10  // Méthode commune à tous les dinosaures
11  this.feed = function() {
12    this.hunger -= 30;
13    if (this.hunger < 0) this.hunger = 0;
14    return `${this.name} a été nourri(e). Niveau de faim : ${this.hunger}%`;
15  };
16}
17
18// Création de nouvelles instances de dinosaures
19const blue = new Dinosaur("Blue", "Velociraptor", 4, "carnivore");
20const trixie = new Dinosaur("Trixie", "Triceratops", 6, "herbivore");
21const rex = new Dinosaur("Rex", "Tyrannosaurus", 8, "carnivore");
22
23console.log(blue.species); // "Velociraptor"
24console.log(trixie.diet); // "herbivore"
25console.log(rex.feed()); // "Rex a été nourri(e). Niveau de faim : 20%"

La fonction constructeur crée un "modèle" pour les objets, et l'opérateur new crée une nouvelle instance d'objet d'après ce modèle.

Les avantages des constructeurs :

  1. Cohérence - tous les objets ont le même ensemble de propriétés et de méthodes
  2. Évolutivité - il est plus facile de créer de nombreux objets similaires
  3. Lisibilité - le code devient plus prévisible et plus facile à maintenir

Vérifier le type d'un objet - l'opérateur instanceof

Nous pouvons vérifier si un objet a été créé à l'aide d'un constructeur précis :

1console.log(blue instanceof Dinosaur); // true
2console.log(velociraptor instanceof Dinosaur); // false (il a été créé sous forme de littéral)

Les classes (ES6+)

Les versions plus récentes de JavaScript (ES6+) ont introduit les classes, qui offrent une syntaxe plus conviviale pour la programmation orientée objet. Sous le capot, ce sont toujours des fonctions constructeurs, mais avec une syntaxe plus lisible.

1class Dinosaur {
2  constructor(name, species, age, diet) {
3    this.name = name;
4    this.species = species;
5    this.age = age;
6    this.diet = diet;
7    this.health = 100;
8    this.hunger = 50;
9    this.isAsleep = false;
10  }
11
12  // Les méthodes sont automatiquement ajoutées au prototype
13  feed() {
14    if (this.isAsleep) {
15      return `${this.name} dort. Mieux vaut ne pas le/la réveiller pendant le nourrissage.`;
16    }
17
18    this.hunger -= 30;
19    if (this.hunger < 0) this.hunger = 0;
20    return `${this.name} a été nourri(e). Niveau de faim : ${this.hunger}%`;
21  }
22
23  sleep() {
24    this.isAsleep = true;
25    return `${this.name} s'endort.`;
26  }
27
28  wakeUp() {
29    this.isAsleep = false;
30    return `${this.name} se réveille.`;
31  }
32
33  getStatus() {
34    return `
35Dinosaure : ${this.name} (Espèce : ${this.species})
36Âge : ${this.age} ans
37Régime : ${this.diet === "carnivore" ? "Carnivore" : "Herbivore"}
38État de santé : ${this.health}%
39Niveau de faim : ${this.hunger}%
40État : ${this.isAsleep ? "Endormi" : "Actif"}`;
41  }
42}
43
44// Création d'une instance de la classe
45const blue = new Dinosaur("Blue", "Velociraptor", 4, "carnivore");
46console.log(blue.getStatus());
47
48console.log(blue.sleep()); // "Blue s'endort."
49console.log(blue.feed()); // "Blue dort. Mieux vaut ne pas le/la réveiller pendant le nourrissage."
50console.log(blue.wakeUp()); // "Blue se réveille."
51console.log(blue.feed()); // "Blue a été nourri(e). Niveau de faim : 20%"

L'héritage avec les classes

Les classes permettent d'implémenter facilement l'héritage :

1// Classe de base
2class Animal {
3  constructor(name, species) {
4    this.name = name;
5    this.species = species;
6    this.alive = true;
7  }
8
9  makeSound() {
10    return "L'animal émet un son";
11  }
12}
13
14// Classe dérivée qui hérite de Animal
15class Dinosaur extends Animal {
16  constructor(name, species, diet) {
17    // On appelle le constructeur de la classe de base
18    super(name, species);
19    this.diet = diet;
20    this.health = 100;
21  }
22
23  // On redéfinit la méthode de la classe de base
24  makeSound() {
25    if (this.diet === "carnivore") {
26      return "ROAR !!! Un rugissement terrifiant !";
27    } else {
28      return "Un grondement doux et grave.";
29    }
30  }
31
32  // On ajoute de nouvelles méthodes
33  eat(food) {
34    if (this.diet === "carnivore" && food.type === "meat") {
35      return `${this.name} dévore ${food.name} avec appétit !`;
36    } else if (this.diet === "herbivore" && food.type === "plant") {
37      return `${this.name} broute ${food.name} avec satisfaction.`;
38    } else {
39      return `${this.name} n'a aucune envie de manger ${food.name}.`;
40    }
41  }
42}
43
44// Objets qui représentent la nourriture
45const meat = { name: "la viande", type: "meat" };
46const plants = { name: "les plantes", type: "plant" };
47
48// On crée des instances de dinosaures
49const rex = new Dinosaur("Rex", "Tyrannosaurus", "carnivore");
50const spike = new Dinosaur("Spike", "Stegosaurus", "herbivore");
51
52console.log(rex.makeSound()); // "ROAR !!! Un rugissement terrifiant !"
53console.log(spike.makeSound()); // "Un grondement doux et grave."
54
55console.log(rex.eat(meat)); // "Rex dévore la viande avec appétit !"
56console.log(rex.eat(plants)); // "Rex n'a aucune envie de manger les plantes."
57console.log(spike.eat(plants)); // "Spike broute les plantes avec satisfaction."

Les méthodes statiques

Les méthodes statiques sont appelées sur la classe elle-même, et non sur ses instances :

1class DinosaurDatabase {
2  static dinoCount = 0;
3
4  constructor(name, species) {
5    this.name = name;
6    this.species = species;
7    DinosaurDatabase.dinoCount++;
8  }
9
10  // Méthode d'instance - nécessite de créer un objet
11  getInfo() {
12    return `${this.name} (${this.species})`;
13  }
14
15  // Méthode statique - appelée sur la classe, pas sur une instance
16  static getTotalDinosaurCount() {
17    return `Nombre total de dinosaures dans la base : ${DinosaurDatabase.dinoCount}`;
18  }
19
20  static compareAge(dino1, dino2) {
21    if (!dino1.age || !dino2.age) return "Aucune donnée sur l'âge.";
22
23    if (dino1.age > dino2.age) {
24      return `${dino1.name} est plus âgé que ${dino2.name}.`;
25    } else if (dino1.age < dino2.age) {
26      return `${dino1.name} est plus jeune que ${dino2.name}.`;
27    } else {
28      return `${dino1.name} et ${dino2.name} ont le même âge.`;
29    }
30  }
31}
32
33const dino1 = new DinosaurDatabase("Rex", "Tyrannosaurus");
34dino1.age = 8;
35
36const dino2 = new DinosaurDatabase("Blue", "Velociraptor");
37dino2.age = 4;
38
39const dino3 = new DinosaurDatabase("Trixie", "Triceratops");
40dino3.age = 6;
41
42console.log(DinosaurDatabase.getTotalDinosaurCount()); // "Nombre total de dinosaures dans la base : 3"
43console.log(DinosaurDatabase.compareAge(dino1, dino2)); // "Rex est plus âgé que Blue."
44console.log(DinosaurDatabase.compareAge(dino2, dino3)); // "Blue est plus jeune que Trixie."

Object.create()

La méthode Object.create() permet de créer de nouveaux objets avec un prototype déterminé :

1// Objet prototype pour tous les dinosaures
2const dinoPrototype = {
3  makeSound() {
4    return "Rugissement !";
5  },
6  eat() {
7    return `${this.name} mange.`;
8  }
9};
10
11// Création d'un objet avec le prototype dinoPrototype
12const rex = Object.create(dinoPrototype);
13rex.name = "Rex";
14rex.species = "Tyrannosaurus";
15
16console.log(rex.name); // "Rex"
17console.log(rex.makeSound()); // "Rugissement !"
18console.log(rex.eat()); // "Rex mange."

Factory Functions (fonctions fabriques)

Les fonctions fabriques sont des fonctions qui créent et renvoient des objets sans utiliser new :

1// Fonction fabrique pour créer des objets dinosaures
2function createDinosaur(name, species, diet) {
3  return {
4    name,  // Syntaxe raccourcie pour name: name en ES6+
5    species,
6    diet,
7    health: 100,
8    hunger: 50,
9
10    feed() {
11      this.hunger -= 30;
12      if (this.hunger < 0) this.hunger = 0;
13      return `${this.name} a été nourri(e). Niveau de faim : ${this.hunger}%`;
14    },
15
16    getStatus() {
17      return `${this.name} (${this.species}) - Santé : ${this.health}%, Faim : ${this.hunger}%`;
18    }
19  };
20}
21
22const blue = createDinosaur("Blue", "Velociraptor", "carnivore");
23const trixie = createDinosaur("Trixie", "Triceratops", "herbivore");
24
25console.log(blue.getStatus()); // "Blue (Velociraptor) - Santé : 100%, Faim : 50%"
26console.log(blue.feed()); // "Blue a été nourri(e). Niveau de faim : 20%"

Utilisation pratique des objets à Jurassic Park

Le système de gestion des dinosaures

1class DinosaurManager {
2  constructor() {
3    this.dinosaurs = [];
4    this.enclosures = [];
5  }
6
7  addDinosaur(dino) {
8    this.dinosaurs.push(dino);
9    console.log(`Nouveau dinosaure ajouté : ${dino.name} (${dino.species})`);
10  }
11
12  addEnclosure(enclosure) {
13    this.enclosures.push(enclosure);
14    console.log(`Nouvel enclos ajouté : ${enclosure.name} (Capacité : ${enclosure.capacity})`);
15  }
16
17  assignDinosaurToEnclosure(dinoName, enclosureName) {
18    const dino = this.dinosaurs.find(d => d.name === dinoName);
19    const enclosure = this.enclosures.find(e => e.name === enclosureName);
20
21    if (!dino) {
22      return `Erreur : dinosaure nommé ${dinoName} introuvable.`;
23    }
24
25    if (!enclosure) {
26      return `Erreur : enclos nommé ${enclosureName} introuvable.`;
27    }
28
29    if (enclosure.dinosaurs.length >= enclosure.capacity) {
30      return `Erreur : l'enclos ${enclosureName} a atteint sa capacité maximale.`;
31    }
32
33    // On vérifie que les prédateurs ne sont pas mélangés aux herbivores
34    if (enclosure.dinosaurs.length > 0) {
35      const existingDiet = enclosure.dinosaurs[0].diet;
36      if (dino.diet === "carnivore" && existingDiet === "herbivore") {
37        return "Erreur : impossible de placer des prédateurs avec des herbivores !";
38      }
39      if (dino.diet === "herbivore" && existingDiet === "carnivore") {
40        return "Erreur : impossible de placer des herbivores avec des prédateurs !";
41      }
42    }
43
44    // On retire le dinosaure de son enclos précédent, s'il y était affecté
45    this.enclosures.forEach(e => {
46      const index = e.dinosaurs.findIndex(d => d.name === dinoName);
47      if (index !== -1) {
48        e.dinosaurs.splice(index, 1);
49      }
50    });
51
52    // On affecte le dinosaure au nouvel enclos
53    enclosure.dinosaurs.push(dino);
54    dino.enclosure = enclosureName;
55
56    return `${dinoName} a été affecté(e) à l'enclos ${enclosureName}.`;
57  }
58
59  getEnclosureReport(enclosureName) {
60    const enclosure = this.enclosures.find(e => e.name === enclosureName);
61
62    if (!enclosure) {
63      return `Erreur : enclos nommé ${enclosureName} introuvable.`;
64    }
65
66    let report = `=== RAPPORT DE L'ENCLOS : ${enclosure.name} ===
67Capacité : ${enclosure.dinosaurs.length}/${enclosure.capacity}
68Statut : ${enclosure.status}
69Dinosaures :\n`;
70
71    if (enclosure.dinosaurs.length === 0) {
72      report += "Aucun dinosaure dans cet enclos.";
73    } else {
74      enclosure.dinosaurs.forEach(dino => {
75        report += `- ${dino.name} (${dino.species}) : Santé : ${dino.health}%, Faim : ${dino.hunger}%\n`;
76      });
77    }
78
79    return report;
80  }
81}
82
83// Classe pour les dinosaures
84class Dinosaur {
85  constructor(name, species, diet) {
86    this.name = name;
87    this.species = species;
88    this.diet = diet;
89    this.health = 100;
90    this.hunger = 50;
91    this.enclosure = null; // Nom de l'enclos auquel le dinosaure est affecté
92  }
93}
94
95// Classe pour les enclos
96class Enclosure {
97  constructor(name, capacity, security) {
98    this.name = name;
99    this.capacity = capacity;
100    this.security = security; // niveau de sécurité
101    this.status = "Operational";
102    this.dinosaurs = []; // Liste des dinosaures présents dans l'enclos
103  }
104}
105
106// Utilisation du système de gestion
107const parkManager = new DinosaurManager();
108
109// Création des enclos
110const carnivoreEnclosure = new Enclosure("Paddock A", 3, "Maximum");
111const herbivoreEnclosure = new Enclosure("Paddock B", 5, "Standard");
112
113parkManager.addEnclosure(carnivoreEnclosure);
114parkManager.addEnclosure(herbivoreEnclosure);
115
116// Création des dinosaures
117const rex = new Dinosaur("Rex", "Tyrannosaurus", "carnivore");
118const blue = new Dinosaur("Blue", "Velociraptor", "carnivore");
119const trixie = new Dinosaur("Trixie", "Triceratops", "herbivore");
120const spike = new Dinosaur("Spike", "Stegosaurus", "herbivore");
121
122parkManager.addDinosaur(rex);
123parkManager.addDinosaur(blue);
124parkManager.addDinosaur(trixie);
125parkManager.addDinosaur(spike);
126
127// Affectation des dinosaures aux enclos
128console.log(parkManager.assignDinosaurToEnclosure("Rex", "Paddock A"));
129console.log(parkManager.assignDinosaurToEnclosure("Blue", "Paddock A"));
130console.log(parkManager.assignDinosaurToEnclosure("Trixie", "Paddock B"));
131console.log(parkManager.assignDinosaurToEnclosure("Spike", "Paddock B"));
132
133// Tentative d'affecter un herbivore à l'enclos des prédateurs
134console.log(parkManager.assignDinosaurToEnclosure("Trixie", "Paddock A"));
135
136// Affichage des rapports
137console.log(parkManager.getEnclosureReport("Paddock A"));
138console.log(parkManager.getEnclosureReport("Paddock B"));

Résumé

Les objets sont un élément fondamental du langage JavaScript et nous permettent de modéliser des structures de données et des comportements complexes. À Jurassic Park, nous les utilisons pour tout représenter - des dinosaures jusqu'au système de gestion du parc tout entier.

Nous disposons de plusieurs façons de créer des objets :

  1. Les littéraux d'objet - la façon la plus simple, idéale pour des objets isolés et uniques
  2. Les fonctions constructeurs - quand nous devons créer de nombreux objets similaires
  3. Les classes (ES6+) - une syntaxe moderne et lisible pour créer des modèles d'objets avec héritage
  4. Object.create() - la création d'objets avec un prototype déterminé
  5. Les fonctions fabriques - des fonctions qui renvoient de nouveaux objets, une alternative aux constructeurs

Le choix d'une technique précise dépend de la situation et des besoins du projet. Dans les applications complexes, comme notre système de gestion de Jurassic Park, nous utilisons le plus souvent une combinaison de ces techniques.

Code de cette leçon : index.js
1// Objets - création - Parc Jurassique
2console.log("Laboratoire des Objets JavaScript");
3console.log("Création et construction d'objets\n");
4
5// ===========================================
6// 1. LITTÉRAUX D'OBJETS (la façon la plus simple)
7// ===========================================
8console.log("=== 1. Littéraux d'objets ===");
9
10// Objet de base
11const dinosaur1 = {
12  name: "T-Rex",
13  species: "Tyrannosaurus Rex",
14  age: 8,
15  weight: 8000,
16  carnivore: true
17};
18
19console.log("Dinosaure 1:");
20console.log(`   Nom: ${dinosaur1.name}`);
21console.log(`   Espèce: ${dinosaur1.species}`);
22console.log(`   Âge: ${dinosaur1.age} ans`);
23
24// Objet avec des méthodes
25const dinosaur2 = {
26  name: "Blue",
27  species: "Velociraptor",
28  speed: 40,
29
30  // Méthode traditionnelle
31  roar: function() {
32    return `${this.name} rugit: SHREEK!`;
33  },
34
35  // Méthode abrégée (ES6)
36  run() {
37    return `${this.name} court à ${this.speed} km/h`;
38  }
39};
40
41console.log("\nDinosaure 2:");
42console.log(`   ${dinosaur2.roar()}`);
43console.log(`   ${dinosaur2.run()}`);
44
45// ===========================================
46// 2. FONCTIONS CONSTRUCTEURS
47// ===========================================
48console.log("\n=== 2. Fonctions constructeurs ===");
49
50function Dinosaur(name, species, age, weight, carnivore) {
51  this.name = name;
52  this.species = species;
53  this.age = age;
54  this.weight = weight;
55  this.carnivore = carnivore;
56
57  this.getInfo = function() {
58    return `${this.name} (${this.species}) - ${this.age} ans, ${this.weight}kg`;
59  };
60
61  this.roar = function() {
62    return `${this.name} rugit: ROAARRR!`;
63  };
64}
65
66const trex = new Dinosaur("Rexy", "T-Rex", 8, 8000, true);
67const trike = new Dinosaur("Trike", "Triceratops", 7, 9000, false);
68
69console.log("\nCréé via un constructeur:");
70console.log(`   ${trex.getInfo()}`);
71console.log(`   ${trex.roar()}`);
72console.log(`   ${trike.getInfo()}`);
73
74// ===========================================
75// 3. Object.create()
76// ===========================================
77console.log("\n=== 3. Object.create() ===");
78
79const dinoPrototype = {
80  getInfo() {
81    return `${this.name} (${this.species})`;
82  },
83
84  roar() {
85    return `${this.name}: ROAARRR!`;
86  }
87};
88
89const velociraptor = Object.create(dinoPrototype);
90velociraptor.name = "Charlie";
91velociraptor.species = "Velociraptor";
92velociraptor.age = 5;
93
94console.log("\nCréé via Object.create():");
95console.log(`   ${velociraptor.getInfo()}`);
96console.log(`   ${velociraptor.roar()}`);
97
98// ===========================================
99// 4. CLASSES ES6
100// ===========================================
101console.log("\n=== 4. Classes ES6 ===");
102
103class DinosaurClass {
104  constructor(name, species, age, weight, carnivore) {
105    this.name = name;
106    this.species = species;
107    this.age = age;
108    this.weight = weight;
109    this.carnivore = carnivore;
110  }
111
112  getInfo() {
113    return `${this.name} (${this.species}) - ${this.age} ans, ${this.weight}kg`;
114  }
115
116  roar() {
117    return `${this.name} rugit: ROAARRR!`;
118  }
119
120  isHeavy() {
121    return this.weight > 1000;
122  }
123}
124
125const stego = new DinosaurClass("Stego", "Stegosaurus", 6, 5000, false);
126const brachio = new DinosaurClass("Brachio", "Brachiosaurus", 10, 50000, false);
127
128console.log("\nCréé via une classe:");
129console.log(`   ${stego.getInfo()}`);
130console.log(`   Est-il lourd ? ${stego.isHeavy()}`);
131console.log(`   ${brachio.getInfo()}`);
132console.log(`   Est-il lourd ? ${brachio.isHeavy()}`);
133
134// ===========================================
135// 5. FONCTIONS FABRIQUES (FACTORY FUNCTIONS)
136// ===========================================
137console.log("\n=== 5. Fonctions fabriques (factory) ===");
138
139function createDinosaur(name, species, options = {}) {
140  return {
141    name,
142    species,
143    age: options.age || 5,
144    weight: options.weight || 100,
145    carnivore: options.carnivore || false,
146    sector: options.sector || "A",
147
148    getInfo() {
149      return `${this.name} (${this.species}) - Secteur ${this.sector}`;
150    },
151
152    feed() {
153      console.log(`Nourrissage de ${this.name}`);
154    }
155  };
156}
157
158const dilo = createDinosaur("Dilo", "Dilophosaurus", {
159  age: 4,
160  weight: 400,
161  carnivore: true,
162  sector: "E"
163});
164
165console.log("\nCréé via une fonction fabrique:");
166console.log(`   ${dilo.getInfo()}`);
167dilo.feed();
168
169// ===========================================
170// 6. OBJETS IMBRIQUÉS
171// ===========================================
172console.log("\n=== 6. Objets imbriqués ===");
173
174const park = {
175  name: "Jurassic Park",
176  location: "Isla Nublar",
177
178  sectors: {
179    A: { name: "Zone des carnivores", capacity: 5, current: 2 },
180    B: { name: "Enclos des raptors", capacity: 10, current: 3 },
181    C: { name: "Vallée des herbivores", capacity: 20, current: 8 }
182  },
183
184  stats: {
185    totalDinosaurs: 13,
186    totalVisitors: 1500,
187    securityLevel: "ÉLEVÉ"
188  },
189
190  getReport() {
191    console.log(`\nRapport du parc ${this.name}:`);
192    console.log(`   Localisation: ${this.location}`);
193    console.log(`   Dinosaures: ${this.stats.totalDinosaurs}`);
194    console.log(`   Visiteurs: ${this.stats.totalVisitors}`);
195    console.log(`   Sécurité: ${this.stats.securityLevel}`);
196  }
197};
198
199park.getReport();
200
201console.log("\nSecteurs:");
202Object.entries(park.sectors).forEach(([key, sector]) => {
203  console.log(`   ${key}: ${sector.name} - ${sector.current}/${sector.capacity}`);
204});
205
206// ===========================================
207// 7. GETTERS ET SETTERS
208// ===========================================
209console.log("\n=== 7. Getters et setters ===");
210
211class ManagedDinosaur {
212  constructor(name, species, health) {
213    this.name = name;
214    this.species = species;
215    this._health = health; // Propriété privée (convention)
216  }
217
218  // Getter
219  get health() {
220    return this._health;
221  }
222
223  // Setter avec validation
224  set health(value) {
225    if (value < 0) value = 0;
226    if (value > 100) value = 100;
227    this._health = value;
228    console.log(`   Santé de ${this.name} changée à ${this._health}%`);
229  }
230
231  get status() {
232    if (this._health >= 80) return "En bonne santé";
233    if (this._health >= 50) return "Moyen";
234    return "Critique";
235  }
236}
237
238const managedDino = new ManagedDinosaur("Rex", "T-Rex", 75);
239console.log(`\n${managedDino.name}:`);
240console.log(`   Santé: ${managedDino.health}%`);
241console.log(`   Statut: ${managedDino.status}`);
242
243managedDino.health = 95;
244console.log(`   Nouveau statut: ${managedDino.status}`);
245
246managedDino.health = 150; // Sera limitée à 100
247console.log(`   Statut après dépassement: ${managedDino.status}`);
248
249// ===========================================
250// 8. MÉTHODES ET PROPRIÉTÉS STATIQUES
251// ===========================================
252console.log("\n=== 8. Méthodes et propriétés statiques ===");
253
254class DinoSpecies {
255  static species = [
256    "Tyrannosaurus Rex",
257    "Velociraptor",
258    "Triceratops",
259    "Stegosaurus",
260    "Brachiosaurus"
261  ];
262
263  static isCarnivore(species) {
264    const carnivores = ["Tyrannosaurus Rex", "Velociraptor", "Spinosaurus"];
265    return carnivores.includes(species);
266  }
267
268  static getInfo(species) {
269    const info = {
270      "Tyrannosaurus Rex": { weight: 8000, period: "Crétacé" },
271      "Velociraptor": { weight: 80, period: "Crétacé" },
272      "Triceratops": { weight: 9000, period: "Crétacé" }
273    };
274    return info[species] || { weight: "?", period: "?" };
275  }
276
277  static listAll() {
278    console.log("\nToutes les espèces:");
279    this.species.forEach((s, i) => {
280      const carnivore = this.isCarnivore(s) ? "carnivore" : "herbivore";
281      console.log(`   ${i + 1}. ${carnivore} ${s}`);
282    });
283  }
284}
285
286DinoSpecies.listAll();
287
288console.log("\nVérification des espèces:");
289console.log(`   T-Rex carnivore ? ${DinoSpecies.isCarnivore("Tyrannosaurus Rex")}`);
290console.log(`   Triceratops carnivore ? ${DinoSpecies.isCarnivore("Triceratops")}`);
291
292const trexInfo = DinoSpecies.getInfo("Tyrannosaurus Rex");
293console.log(`\nInfo sur le T-Rex: poids ${trexInfo.weight}kg, période ${trexInfo.period}`);
294
295// ===========================================
296// 9. HÉRITAGE
297// ===========================================
298console.log("\n=== 9. Héritage ===");
299
300class Animal {
301  constructor(name, age) {
302    this.name = name;
303    this.age = age;
304  }
305
306  breathe() {
307    return `${this.name} respire`;
308  }
309
310  getAge() {
311    return `${this.name} a ${this.age} ans`;
312  }
313}
314
315class Carnivore extends Animal {
316  constructor(name, age, huntingSkill) {
317    super(name, age);
318    this.huntingSkill = huntingSkill;
319    this.type = "Carnivore";
320  }
321
322  hunt() {
323    return `${this.name} chasse (compétence: ${this.huntingSkill}/10)`;
324  }
325
326  roar() {
327    return `${this.name} rugit: ROAARRR!`;
328  }
329}
330
331class Herbivore extends Animal {
332  constructor(name, age, plantPreference) {
333    super(name, age);
334    this.plantPreference = plantPreference;
335    this.type = "Herbivore";
336  }
337
338  eat() {
339    return `${this.name} mange ${this.plantPreference}`;
340  }
341
342  graze() {
343    return `${this.name} broute tranquillement`;
344  }
345}
346
347const rex = new Carnivore("Rexy", 8, 10);
348const trico = new Herbivore("Trico", 7, "fougères");
349
350console.log("\nCarnivore:");
351console.log(`   ${rex.getAge()}`);
352console.log(`   ${rex.breathe()}`);
353console.log(`   ${rex.hunt()}`);
354console.log(`   ${rex.roar()}`);
355
356console.log("\nHerbivore:");
357console.log(`   ${trico.getAge()}`);
358console.log(`   ${trico.breathe()}`);
359console.log(`   ${trico.eat()}`);
360console.log(`   ${trico.graze()}`);
361
362// ===========================================
363// 10. EXEMPLE COMPLET
364// ===========================================
365console.log("\n=== 10. Système de gestion - exemple complet ===");
366
367class ParkManagementSystem {
368  constructor(parkName) {
369    this.parkName = parkName;
370    this.dinosaurs = new Map();
371    this.nextId = 1;
372  }
373
374  addDinosaur(name, species, options = {}) {
375    const dino = {
376      id: this.nextId++,
377      name,
378      species,
379      age: options.age || 5,
380      weight: options.weight || 1000,
381      health: options.health || 100,
382      sector: options.sector || "A",
383      carnivore: options.carnivore || false,
384      fed: false,
385      lastCheckup: new Date()
386    };
387
388    this.dinosaurs.set(dino.id, dino);
389    console.log(`Ajouté: ${name} (#${dino.id})`);
390    return dino.id;
391  }
392
393  getDinosaur(id) {
394    return this.dinosaurs.get(id);
395  }
396
397  removeDinosaur(id) {
398    const dino = this.dinosaurs.get(id);
399    if (dino) {
400      this.dinosaurs.delete(id);
401      console.log(`Supprimé: ${dino.name} (#${id})`);
402      return true;
403    }
404    return false;
405  }
406
407  feedDinosaur(id) {
408    const dino = this.dinosaurs.get(id);
409    if (dino) {
410      dino.fed = true;
411      console.log(`Nourri: ${dino.name}`);
412    }
413  }
414
415  updateHealth(id, newHealth) {
416    const dino = this.dinosaurs.get(id);
417    if (dino) {
418      dino.health = Math.max(0, Math.min(100, newHealth));
419      console.log(`Santé mise à jour pour ${dino.name}: ${dino.health}%`);
420    }
421  }
422
423  getStats() {
424    const dinos = Array.from(this.dinosaurs.values());
425
426    return {
427      total: dinos.length,
428      carnivores: dinos.filter(d => d.carnivore).length,
429      avgHealth: (dinos.reduce((sum, d) => sum + d.health, 0) / dinos.length).toFixed(1),
430      fed: dinos.filter(d => d.fed).length,
431      bySector: dinos.reduce((acc, d) => {
432        acc[d.sector] = (acc[d.sector] || 0) + 1;
433        return acc;
434      }, {})
435    };
436  }
437
438  displayReport() {
439    console.log(`\n============================================================`);
440    console.log(`RAPPORT DU PARC: ${this.parkName}`);
441    console.log("=".repeat(60));
442
443    const stats = this.getStats();
444    console.log("\nStatistiques:");
445    console.log(`   Total des dinosaures: ${stats.total}`);
446    console.log(`   Carnivores: ${stats.carnivores}`);
447    console.log(`   Santé moyenne: ${stats.avgHealth}%`);
448    console.log(`   Nourris: ${stats.fed}/${stats.total}`);
449
450    console.log("\nRépartition par secteurs:");
451    Object.entries(stats.bySector).sort().forEach(([sector, count]) => {
452      console.log(`   Secteur ${sector}: ${count}`);
453    });
454
455    console.log("\nListe des dinosaures:");
456    Array.from(this.dinosaurs.values())
457      .sort((a, b) => a.id - b.id)
458      .forEach(dino => {
459        const icon = dino.carnivore ? "carnivore" : "herbivore";
460        const fedStatus = dino.fed ? "√" : "×";
461        console.log(`   #${dino.id} ${icon} ${dino.name} (${dino.species})`);
462        console.log(`       Secteur ${dino.sector} | Santé: ${dino.health}% | Nourri: ${fedStatus}`);
463      });
464  }
465}
466
467// Démonstration du système
468console.log();
469const parkSystem = new ParkManagementSystem("Isla Nublar");
470
471const id1 = parkSystem.addDinosaur("Rexy", "T-Rex", { age: 8, weight: 8000, sector: "A", carnivore: true });
472const id2 = parkSystem.addDinosaur("Blue", "Velociraptor", { age: 5, weight: 80, sector: "B", carnivore: true, health: 100 });
473const id3 = parkSystem.addDinosaur("Charlie", "Velociraptor", { age: 5, weight: 80, sector: "B", carnivore: true, health: 85 });
474const id4 = parkSystem.addDinosaur("Trike", "Triceratops", { age: 7, weight: 9000, sector: "C", health: 70 });
475const id5 = parkSystem.addDinosaur("Stego", "Stegosaurus", { age: 6, weight: 5000, sector: "C" });
476
477console.log();
478parkSystem.feedDinosaur(id1);
479parkSystem.feedDinosaur(id2);
480parkSystem.updateHealth(id4, 85);
481
482parkSystem.displayReport();
483
484console.log("\nFélicitations ! Tu maîtrises maintenant la création d'objets !");

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. Quelles sont les deux façons d'accéder aux propriétés d'un objet en JavaScript ?

  2. 2. Que fait le mot-clé « new » avant l'appel d'une fonction constructeur ?

Tâches pratiques dans le jeu

  • Clique dans l'ordre

    Range les éléments de la création d'un objet dinosaure avec une méthode :

  • Éditeur de code

    Crée un objet dinosaur avec les propriétés name: 'Rexy', species: 'Tyrannosaurus Rex', age: 25 et isCarnivore: true, ainsi qu'un objet imbriqué stats qui a la propriété health: 95. Après avoir créé l'objet, ajoute-lui une propriété enclosure de valeur 'Zone A'. Affiche dans la console name avec la notation pointée et species avec la notation entre crochets.

  • Tri horizontal

    Range les éléments de la création d'un objet avec un littéral :

  • Clique dans l'ordre

    Range les éléments d'une déclaration d'objet avec des propriétés :

  • Tri horizontal

    Range les éléments d'une déclaration d'objet en JavaScript

Articles utiles