JavaScript evolves rapidly! Let's explore the latest language features introduced in ES2024 and ES2025 that make working with our Jurassic Park systems even more elegant.
Group elements by a criterion — no more manual reduce() for grouping!
1const dinosaurs = [
2 { name: "Rexy", species: "Tyrannosaurus", diet: "carnivore", sector: "A" },
3 { name: "Blue", species: "Velociraptor", diet: "carnivore", sector: "B" },
4 { name: "Spike", species: "Triceratops", diet: "herbivore", sector: "C" },
5 { name: "Sarah", species: "Triceratops", diet: "herbivore", sector: "A" },
6 { name: "Delta", species: "Velociraptor", diet: "carnivore", sector: "B" }
7];
8
9// Group by diet — returns a plain object
10const byDiet = Object.groupBy(dinosaurs, dino => dino.diet);
11console.log(byDiet.carnivore.map(d => d.name)); // ["Rexy", "Blue", "Delta"]
12console.log(byDiet.herbivore.map(d => d.name)); // ["Spike", "Sarah"]
13
14// Group by sector — returns a Map
15const bySector = Map.groupBy(dinosaurs, dino => dino.sector);
16console.log(bySector.get("A").map(d => d.name)); // ["Rexy", "Sarah"]
17console.log(bySector.get("B").map(d => d.name)); // ["Blue", "Delta"]New non-mutating array methods that return a new array instead of modifying the original:
1const dinoNames = ["Rexy", "Blue", "Spike", "Delta", "Sarah"];
2
3// toSorted() — non-mutating sort
4const sorted = dinoNames.toSorted();
5console.log(sorted); // ["Blue", "Delta", "Rexy", "Sarah", "Spike"]
6console.log(dinoNames); // ["Rexy", "Blue", "Spike", "Delta", "Sarah"] — unchanged!
7
8// Compare with old sort():
9const old = [...dinoNames].sort(); // Had to copy first
10
11// toReversed() — non-mutating reverse
12const reversed = dinoNames.toReversed();
13console.log(reversed); // ["Sarah", "Delta", "Spike", "Blue", "Rexy"]
14
15// toSpliced() — non-mutating splice
16const withNew = dinoNames.toSpliced(2, 1, "Triki", "Bronto");
17console.log(withNew); // ["Rexy", "Blue", "Triki", "Bronto", "Delta", "Sarah"]
18console.log(dinoNames); // unchanged
19
20// with() — replace a single element by index
21const updated = dinoNames.with(0, "T-Rex Alpha");
22console.log(updated); // ["T-Rex Alpha", "Blue", "Spike", "Delta", "Sarah"]
23console.log(dinoNames); // unchangedExposes the resolve/reject functions outside the Promise constructor:
1// Old way — resolver/rejecter captured via closure
2let resolve, reject;
3const promise = new Promise((res, rej) => {
4 resolve = res;
5 reject = rej;
6});
7
8// New way — cleaner!
9const { promise, resolve, reject } = Promise.withResolvers();
10
11// Useful for creating controllable async operations
12class DinosaurSensor {
13 constructor(id) {
14 this.id = id;
15 const { promise, resolve, reject } = Promise.withResolvers();
16 this.readingPromise = promise;
17 this.resolveReading = resolve;
18 this.rejectReading = reject;
19 }
20
21 receiveReading(data) {
22 this.resolveReading(data);
23 }
24
25 sensorFailure(error) {
26 this.rejectReading(error);
27 }
28}
29
30const sensor = new DinosaurSensor("TREX-001");
31
32// Set up what happens when reading arrives
33sensor.readingPromise.then(reading => {
34 console.log(`Sensor ${sensor.id}: ${JSON.stringify(reading)}`);
35});
36
37// Later, when the reading arrives:
38sensor.receiveReading({ temperature: 38.5, heartRate: 72 });New Set operations for mathematical set algebra:
1const carnivores = new Set(["T-Rex", "Velociraptor", "Spinosaurus"]);
2const largeDinos = new Set(["T-Rex", "Brachiosaurus", "Spinosaurus"]);
3const parkDinos = new Set(["T-Rex", "Velociraptor", "Triceratops"]);
4
5// intersection() — elements in both sets
6const largeCarnivores = carnivores.intersection(largeDinos);
7console.log([...largeCarnivores]); // ["T-Rex", "Spinosaurus"]
8
9// difference() — in first but not second
10const smallCarnivores = carnivores.difference(largeDinos);
11console.log([...smallCarnivores]); // ["Velociraptor"]
12
13// union() — all elements from both
14const allKnown = carnivores.union(largeDinos);
15console.log([...allKnown]); // ["T-Rex", "Velociraptor", "Spinosaurus", "Brachiosaurus"]
16
17// symmetricDifference() — in one but not both
18const uniqueToEach = carnivores.symmetricDifference(largeDinos);
19console.log([...uniqueToEach]); // ["Velociraptor", "Brachiosaurus"]
20
21// isSubsetOf() — are all elements of carnivores in parkDinos?
22console.log(new Set(["T-Rex"]).isSubsetOf(parkDinos)); // true
23console.log(carnivores.isSubsetOf(parkDinos)); // false (Velociraptor is there, Spinosaurus not)
24
25// isSupersetOf() — does parkDinos contain all of the subset?
26console.log(parkDinos.isSupersetOf(new Set(["T-Rex", "Triceratops"]))); // true
27
28// isDisjointFrom() — no elements in common?
29const oceanDinos = new Set(["Mosasaurus", "Plesiosaurus"]);
30console.log(carnivores.isDisjointFrom(oceanDinos)); // trueWraps both synchronous and asynchronous functions uniformly:
1// Without Promise.try — must handle sync/async differently
2function getDinosaurStatus(id) {
3 return new Promise((resolve, reject) => {
4 try {
5 const result = syncOperation(id); // might throw synchronously
6 resolve(asyncOperation(result)); // might reject
7 } catch (e) {
8 reject(e);
9 }
10 });
11}
12
13// With Promise.try — cleaner
14function getDinosaurStatus(id) {
15 return Promise.try(() => {
16 const result = syncOperation(id); // sync throws are caught
17 return asyncOperation(result); // async rejections are caught
18 });
19}
20
21// Practical: safely execute any function as a promise
22const safeCheck = Promise.try(() => {
23 validateDinoId("RAPTOR-001"); // might throw
24 return fetchDinosaurData("RAPTOR-001"); // returns promise
25});
26
27safeCheck
28 .then(data => console.log("Data:", data))
29 .catch(err => console.error("Error:", err));1// Import JSON directly
2import config from './config.json' with { type: 'json' };
3import translations from './i18n/en.json' with { type: 'json' };
4
5// Dynamic import with attributes
6const data = await import('./park-data.json', { with: { type: 'json' } });
7
8console.log(config.parkName); // "Jurassic Park"
9console.log(translations.welcome); // "Welcome to Jurassic Park!"The latest JavaScript features make code more expressive and reduce boilerplate:
These features reflect modern JavaScript's move toward more functional, immutable, and ergonomic patterns — making even the most complex Jurassic Park systems easier to write and maintain!