Welcome to the most advanced laboratory in Jurassic Park! In this module you have mastered ES6 classes, inheritance, template literals, destructuring, rest/spread operators, default parameters, Map and Set collections, and composition. Now you will combine all of these tools to build a professional Species Classification System — a digital taxonomy of dinosaurs in our park.
In the real Jurassic Park, scientists had to not only clone dinosaurs, but also catalog them, classify them, and track the relationships between species. Every species has its own unique traits, belongs to a particular family, has a specific diet, and has specific environmental requirements. Our system must model all of this in an elegant, object-oriented way.
This project is a real challenge — you will use classes with constructors and methods, inheritance to build species hierarchies, destructuring for convenient data handling, Map and Set to manage unique collections, and template literals to generate readable reports. Ready? Let's go!
You will build a classification system that:
Build a class system reflecting dinosaur taxonomy. The base class
Dinosaur should contain common traits, and derived classes add specific behaviors.1// Base class for all dinosaurs
2class Dinosaur {
3 // Static properties shared by all dinosaurs
4 static totalCount = 0;
5 static registry = new Map();
6
7 constructor(name, species, weight, period = "Cretaceous") {
8 this.name = name;
9 this.species = species;
10 this.weight = weight;
11 this.period = period;
12 this.isAlive = true;
13 this._healthStatus = 100;
14
15 // Increment counter for each new dinosaur
16 Dinosaur.totalCount++;
17 Dinosaur.registry.set(name, this);
18 }
19
20 // Getter — calculates size category
21 get sizeCategory() {
22 if (this.weight > 5000) return "colossal";
23 if (this.weight > 1000) return "large";
24 if (this.weight > 100) return "medium";
25 return "small";
26 }
27
28 // Getter and setter for health
29 get health() {
30 return this._healthStatus;
31 }
32
33 set health(value) {
34 this._healthStatus = Math.max(0, Math.min(100, value));
35 if (this._healthStatus === 0) {
36 this.isAlive = false;
37 console.log(`[ALERT] ${this.name} has died!`);
38 }
39 }
40
41 // Instance method — dinosaur information
42 getInfo() {
43 return `${this.name} (${this.species}) - ${this.weight}kg, ${this.period}`;
44 }
45
46 // Static method — retrieve a dinosaur from the registry
47 static find(name) {
48 return Dinosaur.registry.get(name) || null;
49 }
50}
51
52// Class for predators
53class Carnivore extends Dinosaur {
54 constructor(name, species, weight, huntingStyle, period) {
55 super(name, species, weight, period);
56 this.diet = "carnivore";
57 this.huntingStyle = huntingStyle;
58 this.preyList = [];
59 }
60
61 addPrey(...preyNames) {
62 this.preyList.push(...preyNames);
63 console.log(`${this.name} hunts: ${this.preyList.join(", ")}`);
64 }
65
66 getInfo() {
67 return `${super.getInfo()} | Predator (${this.huntingStyle})`;
68 }
69}
70
71// Class for herbivores
72class Herbivore extends Dinosaur {
73 constructor(name, species, weight, defenseType, period) {
74 super(name, species, weight, period);
75 this.diet = "herbivore";
76 this.defenseType = defenseType;
77 this.preferredPlants = new Set();
78 }
79
80 addPlants(...plants) {
81 plants.forEach(plant => this.preferredPlants.add(plant));
82 console.log(`${this.name} prefers: ${[...this.preferredPlants].join(", ")}`);
83 }
84
85 getInfo() {
86 return `${super.getInfo()} | Herbivore (defense: ${this.defenseType})`;
87 }
88}
89
90// Creating instances
91const rex = new Carnivore("Rex", "Tyrannosaurus Rex", 8500, "ambush");
92const blue = new Carnivore("Blue", "Velociraptor", 75, "pack hunting");
93const tricia = new Herbivore("Tricia", "Triceratops", 6200, "horns");
94const dippy = new Herbivore("Dippy", "Diplodocus", 12000, "tail whip", "Jurassic");
95
96rex.addPrey("Triceratops", "Hadrosaur", "Gallimimus");
97tricia.addPlants("ferns", "cycads", "conifers");
98tricia.addPlants("ferns"); // Set ignores duplicates!
99
100console.log(rex.getInfo());
101console.log(tricia.getInfo());
102console.log("Rex size:", rex.sizeCategory);
103console.log("Total dinosaurs:", Dinosaur.totalCount);The system must manage a species catalog, tracking unique traits and relationships.
Map and Set collections are perfect for this.1// Map — species catalog with metadata
2const speciesCatalog = new Map();
3
4speciesCatalog.set("Tyrannosaurus Rex", {
5 family: "Tyrannosauridae",
6 period: "Late Cretaceous",
7 region: "North America",
8 avgWeight: 8000,
9 dangerLevel: 10
10});
11
12speciesCatalog.set("Velociraptor", {
13 family: "Dromaeosauridae",
14 period: "Late Cretaceous",
15 region: "Central Asia",
16 avgWeight: 70,
17 dangerLevel: 8
18});
19
20speciesCatalog.set("Triceratops", {
21 family: "Ceratopsidae",
22 period: "Late Cretaceous",
23 region: "North America",
24 avgWeight: 6000,
25 dangerLevel: 4
26});
27
28speciesCatalog.set("Diplodocus", {
29 family: "Diplodocidae",
30 period: "Late Jurassic",
31 region: "North America",
32 avgWeight: 12000,
33 dangerLevel: 2
34});
35
36// Iterating over Map with destructuring
37console.log("=== SPECIES CATALOG ===");
38for (const [species, data] of speciesCatalog) {
39 const { family, period, dangerLevel } = data;
40 console.log(`${species}: family ${family}, ${period}, danger: ${dangerLevel}/10`);
41}
42
43// Set — unique geological periods
44const periods = new Set();
45for (const [, data] of speciesCatalog) {
46 periods.add(data.period);
47}
48console.log("Geological periods:", [...periods]);
49
50// Set — unique regions
51const regions = new Set(
52 [...speciesCatalog.values()].map(data => data.region)
53);
54console.log("Regions:", [...regions]);
55
56// Membership checks
57console.log("Do we have T-Rex?", speciesCatalog.has("Tyrannosaurus Rex"));
58console.log("Do we have Pteranodon?", speciesCatalog.has("Pteranodon"));
59console.log("Number of species:", speciesCatalog.size);The system must generate readable text reports. Multi-line template literals with expressions are the ideal tool.
1// Function generating a species report using template literals
2function generateSpeciesReport(dinosaur) {
3 const { name, species, weight, diet, isAlive } = dinosaur;
4 const catalogEntry = speciesCatalog.get(species);
5
6 // Destructuring with default values
7 const {
8 family = "Unknown",
9 period = "Unknown",
10 dangerLevel = 0
11 } = catalogEntry || {};
12
13 const dangerBar = "█".repeat(dangerLevel) + "░".repeat(10 - dangerLevel);
14
15 return `
16╔══════════════════════════════════════╗
17║ SPECIES REPORT - JURASSIC PARK ║
18╠══════════════════════════════════════╣
19║ Name: ${name}
20║ Species: ${species}
21║ Family: ${family}
22║ Period: ${period}
23║ Weight: ${weight} kg
24║ Diet: ${diet === "carnivore" ? "Carnivore" : "Herbivore"}
25║ Status: ${isAlive ? "Alive" : "Dead"}
26║ Danger: [${dangerBar}] ${dangerLevel}/10
27╚══════════════════════════════════════╝`;
28}
29
30// Generating reports
31console.log(generateSpeciesReport(rex));
32console.log(generateSpeciesReport(tricia));
33
34// Summary report using spread and reduce
35function generateParkSummary(...allDinosaurs) {
36 const totalWeight = allDinosaurs.reduce((sum, d) => sum + d.weight, 0);
37 const carnivoreCount = allDinosaurs.filter(d => d.diet === "carnivore").length;
38 const herbivoreCount = allDinosaurs.filter(d => d.diet === "herbivore").length;
39
40 const dinoList = allDinosaurs
41 .map(d => ` - ${d.name} (${d.species})`)
42 .join("\n");
43
44 return `
45=== PARK SUMMARY ===
46Total dinosaurs: ${allDinosaurs.length}
47Predators: ${carnivoreCount}
48Herbivores: ${herbivoreCount}
49Total weight: ${totalWeight.toLocaleString()} kg
50
51Specimen list:
52${dinoList}
53====================`;
54}
55
56console.log(generateParkSummary(rex, blue, tricia, dippy));The system must flexibly process data from different sources. Destructuring and spread/rest operators make this elegant.
1// Object destructuring — extracting data from the catalog
2const trexData = speciesCatalog.get("Tyrannosaurus Rex");
3const { family, dangerLevel, avgWeight, ...restData } = trexData;
4console.log("T-Rex family:", family);
5console.log("Danger level:", dangerLevel);
6console.log("Remaining data:", restData);
7
8// Array destructuring — sorting population
9const sortedByWeight = [rex, blue, tricia, dippy].sort((a, b) => b.weight - a.weight);
10const [heaviest, secondHeaviest, ...others] = sortedByWeight;
11console.log("Heaviest:", heaviest.name, "-", heaviest.weight, "kg");
12console.log("Second:", secondHeaviest.name, "-", secondHeaviest.weight, "kg");
13console.log("Others:", others.map(d => d.name));
14
15// Spread — merging collections
16const parkAnimals = [...[rex, blue], ...[tricia, dippy]];
17console.log("All animals:", parkAnimals.map(d => d.name));
18
19// Spread — copying and extending objects
20const rexProfile = {
21 name: rex.name,
22 species: rex.species,
23 weight: rex.weight
24};
25
26const extendedProfile = {
27 ...rexProfile,
28 enclosure: "A-1",
29 feedingSchedule: ["08:00", "14:00", "20:00"],
30 lastCheckup: "2024-03-10"
31};
32console.log("Extended profile:", extendedProfile);
33
34// Function with parameter destructuring
35function classifyDinosaur({ species, weight, diet }) {
36 const threatLevel = diet === "carnivore"
37 ? (weight > 1000 ? "CRITICAL" : "HIGH")
38 : (weight > 5000 ? "LOW" : "MINIMAL");
39
40 return `${species}: threat ${threatLevel}`;
41}
42
43// Passing an object — destructuring in the parameter
44console.log(classifyDinosaur(rex));
45console.log(classifyDinosaur(tricia));
46console.log(classifyDinosaur(blue));
47
48// Function with default parameter and rest
49function createEnclosure(name, capacity = 5, ...initialResidents) {
50 const enclosure = {
51 name,
52 capacity,
53 residents: new Set(initialResidents),
54 isFull() {
55 return this.residents.size >= this.capacity;
56 },
57 addResident(dino) {
58 if (this.isFull()) {
59 console.log(`Enclosure ${this.name} is full!`);
60 return false;
61 }
62 this.residents.add(dino);
63 return true;
64 }
65 };
66
67 console.log(`Created enclosure "${name}" (capacity: ${capacity})`);
68 console.log(`Initial residents: ${[...enclosure.residents].join(", ")}`);
69 return enclosure;
70}
71
72const paddockA = createEnclosure("Paddock Alpha", 3, "Rex", "Blue");
73paddockA.addResident("Echo");
74paddockA.addResident("Delta"); // full!
75console.log("Paddock Alpha full:", paddockA.isFull());
76
77// Inverting keys and values in Map
78const dangerIndex = new Map();
79for (const [species, data] of speciesCatalog) {
80 dangerIndex.set(data.dangerLevel, [
81 ...(dangerIndex.get(data.dangerLevel) || []),
82 species
83 ]);
84}
85
86console.log("=== DANGER INDEX ===");
87for (const [level, speciesList] of [...dangerIndex].sort((a, b) => b[0] - a[0])) {
88 console.log(`Level ${level}: ${speciesList.join(", ")}`);
89}When building the Species Classification System, keep these principles in mind:
extends) — use when classes have an "is a kind of" relationship (Carnivore is a kind of Dinosaur), not for every shared traitsuper() — always call in the derived class constructor before using this${expression} interpolation...) — for copying arrays/objects (immutability!) and merging collections...args) — in function parameters for a variable number of argumentssize and iterationTime for the most important task in the Jurassic Park laboratory! Build your own Species Classification System in the editor below. Combine classes, inheritance, destructuring, template literals, Map, Set, and spread/rest operators into one professional taxonomic system. Every dinosaur species deserves precise classification — from the tiny Compsognathus to the mighty Tyrannosaurus Rex!
As Dr. Alan Grant said: "Dinosaurs and man — two species separated by 65 million years of evolution, suddenly thrown together." Your code is the bridge between those worlds!