Retour au blog

ECMAScript 2025 : Les Nouvelles Fonctionnalités JavaScript Que Vous Devez Connaître

Salut HaWkers, ECMAScript 2025 a été officiellement approuvé et apporte une série de fonctionnalités qui vont faciliter la vie des développeurs JavaScript. Des améliorations des expressions régulières aux nouveaux types d'array pour les graphiques et le machine learning, cette mise à jour a quelque chose pour tout le monde.

Vous êtes-vous déjà demandé comment JavaScript continue d'évoluer année après année ? Explorons chaque nouvelle fonctionnalité d'ES2025 avec des exemples pratiques que vous pouvez commencer à utiliser aujourd'hui.

Vue d'Ensemble des Nouveautés

Avant de plonger dans les détails, voici un résumé de ce qu'ECMAScript 2025 apporte :

Principales additions :

  • Promise.try() - Exécution sécurisée de fonctions synchrones
  • Float16Array - Nouveau TypedArray de demi-précision
  • Duplicate Named Capture Groups - Regex plus flexible
  • RegExp.escape() - Échappement automatique de caractères spéciaux
  • Set methods - Opérations d'ensemble natives
  • Iterator helpers - Méthodes auxiliaires pour itérateurs

💡 Contexte : JavaScript reçoit des mises à jour annuelles depuis 2015 (ES6), maintenant le langage moderne et compétitif.

Promise.try() : Traitement Uniforme des Fonctions

L'une des fonctionnalités les plus pratiques d'ES2025 est Promise.try(), qui résout un problème courant : exécuter des fonctions qui peuvent être synchrones ou asynchrones.

L'Ancien Problème

Avant, si vous aviez une fonction qui pouvait lancer une erreur de façon synchrone, vous aviez besoin d'un traitement spécial :

// Problème : si getUser lance une erreur synchrone, le catch ne l'attrape pas
function fetchUserData(userId) {
  // Si userId est invalide, cela lance une erreur AVANT la Promise
  const user = getUser(userId); // Peut lancer une erreur synchrone !
  return Promise.resolve(user)
    .then(user => processUser(user))
    .catch(err => handleError(err)); // N'attrape pas les erreurs synchrones !
}

// Ancienne solution : envelopper dans try-catch ou Promise
function fetchUserDataSafe(userId) {
  return new Promise((resolve, reject) => {
    try {
      const user = getUser(userId);
      resolve(user);
    } catch (err) {
      reject(err);
    }
  }).then(user => processUser(user))
    .catch(err => handleError(err));
}

La Solution avec Promise.try()

Maintenant, tout devient plus simple :

// ES2025 : Promise.try résout le problème élégamment
function fetchUserData(userId) {
  return Promise.try(() => getUser(userId))
    .then(user => processUser(user))
    .catch(err => handleError(err));
}

// Fonctionne avec les fonctions async aussi
function fetchUserDataAsync(userId) {
  return Promise.try(async () => {
    const user = await getUser(userId);
    const profile = await getProfile(user.id);
    return { user, profile };
  })
    .then(data => processData(data))
    .catch(err => handleError(err));
}

// Exemple pratique : validation et fetch
function loadResource(resourceId) {
  return Promise.try(() => {
    // Validation synchrone qui peut lancer une erreur
    if (!isValidId(resourceId)) {
      throw new Error('ID invalide');
    }
    // Opération asynchrone
    return fetch(`/api/resources/${resourceId}`);
  })
    .then(response => response.json())
    .catch(err => {
      console.error('Erreur lors du chargement de la ressource:', err);
      return null;
    });
}

Float16Array : Précision pour Graphiques et ML

Le nouveau Float16Array ajoute le support pour les nombres à virgule flottante de 16 bits, essentiel pour les graphiques et le machine learning.

Pourquoi 16 Bits ?

Comparaison de précision :

Type Bits Mémoire Usage
Float16 16 2 octets Graphiques, ML
Float32 32 4 octets Usage général
Float64 64 8 octets Haute précision

Utiliser Float16Array

// Créer un Float16Array
const halfFloats = new Float16Array(4);
halfFloats[0] = 1.5;
halfFloats[1] = 2.25;
halfFloats[2] = 0.125;
halfFloats[3] = -3.75;

console.log(halfFloats); // Float16Array(4) [1.5, 2.25, 0.125, -3.75]

// Créer à partir d'un array existant
const values = [0.5, 1.0, 1.5, 2.0, 2.5];
const f16 = Float16Array.from(values);

// Utile pour WebGL et WebGPU
const vertexData = new Float16Array([
  // x, y, z, u, v
  -1.0, -1.0, 0.0, 0.0, 0.0,
   1.0, -1.0, 0.0, 1.0, 0.0,
   0.0,  1.0, 0.0, 0.5, 1.0,
]);

// Économie de mémoire pour ML
const weights = new Float16Array(1000000); // 2MB vs 4MB avec Float32

Fonctions Auxiliaires

// Nouvelles fonctions Math pour Float16
const f16Value = Math.f16round(3.14159); // Arrondit à la précision f16
console.log(f16Value); // 3.140625

// Utile pour shaders et GPU computing
function prepareGPUData(floatArray) {
  // Convertit Float32 en Float16 pour envoyer au GPU
  const f16Data = Float16Array.from(floatArray);
  return f16Data.buffer;
}

// DataView supporte aussi Float16
const buffer = new ArrayBuffer(8);
const view = new DataView(buffer);

view.setFloat16(0, 1.5);           // Écrit Float16
view.setFloat16(2, 2.5, true);     // Little-endian

const value1 = view.getFloat16(0); // Lit Float16
const value2 = view.getFloat16(2, true);

Duplicate Named Capture Groups

Une limitation frustrante des regex a été résolue : maintenant vous pouvez utiliser le même nom de groupe dans différentes parties d'une expression régulière.

L'Ancien Problème

// Avant : c'était une erreur de syntaxe
// const dateRegex = /(?<day>\d{2})-(?<month>\d{2})|(?<month>\d{2})\/(?<day>\d{2})/;
// SyntaxError: Duplicate capture group name

// Ancienne solution : noms différents
const dateRegexOld = /(?<day1>\d{2})-(?<month1>\d{2})|(?<month2>\d{2})\/(?<day2>\d{2})/;
const match = '25-12'.match(dateRegexOld);
// Devait vérifier quel groupe a matché
const day = match.groups.day1 || match.groups.day2;
const month = match.groups.month1 || match.groups.month2;

La Solution ES2025

// ES2025 : même nom dans des alternatives différentes
const dateRegex = /(?<day>\d{2})-(?<month>\d{2})|(?<month>\d{2})\/(?<day>\d{2})/;

// Format JJ-MM
const match1 = '25-12'.match(dateRegex);
console.log(match1.groups.day);   // "25"
console.log(match1.groups.month); // "12"

// Format MM/JJ
const match2 = '12/25'.match(dateRegex);
console.log(match2.groups.day);   // "25"
console.log(match2.groups.month); // "12"

// Exemple plus complexe : multiples formats de date
const flexibleDate = /
  (?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})|
  (?<day>\d{2})\/(?<month>\d{2})\/(?<year>\d{4})|
  (?<month>\d{2})-(?<day>\d{2})-(?<year>\d{4})
/x;

// Tous fonctionnent avec les mêmes noms de groupe
['2025-12-25', '25/12/2025', '12-25-2025'].forEach(date => {
  const m = date.match(flexibleDate);
  console.log(`${m.groups.year}-${m.groups.month}-${m.groups.day}`);
});

RegExp.escape() : Échappement Automatique

Nous avons enfin une façon native d'échapper les chaînes pour utilisation dans les expressions régulières.

Le Problème

// Avant : devait créer sa propre fonction ou utiliser une bibliothèque
function escapeRegex(string) {
  return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
}

// Ou risquer des bugs
const userInput = 'file.txt';
const regex = new RegExp(userInput); // Problème : . matche n'importe quel caractère !
'fileAtxt'.match(regex); // Match non désiré !

La Solution Native

// ES2025 : RegExp.escape()
const userInput = 'file.txt';
const escaped = RegExp.escape(userInput);
console.log(escaped); // "file\\.txt"

const regex = new RegExp(escaped);
'file.txt'.match(regex);  // Match correct
'fileAtxt'.match(regex);  // null - ne matche plus

// Utile pour la recherche de texte littéral
function findExactText(text, searchTerm) {
  const escaped = RegExp.escape(searchTerm);
  const regex = new RegExp(escaped, 'gi');
  return text.match(regex);
}

// Fonctionne avec n'importe quel caractère spécial
const specialChars = '(hello) [world] {test} $100 ^start end$';
const safeRegex = new RegExp(RegExp.escape(specialChars));

// Exemple pratique : surlignage de texte
function highlightText(content, searchTerm) {
  const escaped = RegExp.escape(searchTerm);
  const regex = new RegExp(`(${escaped})`, 'gi');
  return content.replace(regex, '<mark>$1</mark>');
}

highlightText('Prix: $99.99', '$99.99');
// "Prix: <mark>$99.99</mark>"

Set Methods : Opérations d'Ensemble Natives

ES2025 ajoute des méthodes natives pour les opérations courantes sur les ensembles.

Nouvelles Méthodes

const setA = new Set([1, 2, 3, 4, 5]);
const setB = new Set([4, 5, 6, 7, 8]);

// Union : éléments dans A OU B
const union = setA.union(setB);
console.log([...union]); // [1, 2, 3, 4, 5, 6, 7, 8]

// Intersection : éléments dans A ET B
const intersection = setA.intersection(setB);
console.log([...intersection]); // [4, 5]

// Différence : éléments dans A mais pas dans B
const difference = setA.difference(setB);
console.log([...difference]); // [1, 2, 3]

// Différence symétrique : éléments dans A ou B, mais pas les deux
const symmetricDiff = setA.symmetricDifference(setB);
console.log([...symmetricDiff]); // [1, 2, 3, 6, 7, 8]

// Sous-ensemble : A est contenu dans B ?
const small = new Set([4, 5]);
console.log(small.isSubsetOf(setA)); // true
console.log(small.isSubsetOf(setB)); // true

// Sur-ensemble : A contient B ?
console.log(setA.isSupersetOf(small)); // true

// Disjoints : A et B n'ont pas d'éléments en commun ?
const setC = new Set([10, 11, 12]);
console.log(setA.isDisjointFrom(setC)); // true
console.log(setA.isDisjointFrom(setB)); // false

Exemples Pratiques

// Gestion des permissions
const userPermissions = new Set(['read', 'write', 'delete']);
const requiredPermissions = new Set(['read', 'write']);

const hasAccess = requiredPermissions.isSubsetOf(userPermissions);
console.log(hasAccess); // true

// Trouver les tags en commun entre posts
const post1Tags = new Set(['javascript', 'web', 'frontend']);
const post2Tags = new Set(['javascript', 'nodejs', 'backend']);

const commonTags = post1Tags.intersection(post2Tags);
console.log([...commonTags]); // ['javascript']

// Combiner des listes d'utilisateurs sans doublons
const team1 = new Set(['alice', 'bob', 'charlie']);
const team2 = new Set(['bob', 'diana', 'eve']);

const allMembers = team1.union(team2);
console.log([...allMembers]); // ['alice', 'bob', 'charlie', 'diana', 'eve']

Iterator Helpers : Méthodes pour Itérateurs

Maintenant les itérateurs ont des méthodes auxiliaires similaires à celles des arrays.

Méthodes Disponibles

// Créer un itérateur
function* infiniteNumbers() {
  let n = 0;
  while (true) {
    yield n++;
  }
}

// take() : prendre les N premiers éléments
const first5 = infiniteNumbers().take(5);
console.log([...first5]); // [0, 1, 2, 3, 4]

// drop() : sauter les N premiers éléments
const skip3take5 = infiniteNumbers().drop(3).take(5);
console.log([...skip3take5]); // [3, 4, 5, 6, 7]

// map() : transformer les éléments
const doubled = infiniteNumbers()
  .take(5)
  .map(n => n * 2);
console.log([...doubled]); // [0, 2, 4, 6, 8]

// filter() : filtrer les éléments
const evens = infiniteNumbers()
  .take(10)
  .filter(n => n % 2 === 0);
console.log([...evens]); // [0, 2, 4, 6, 8]

// flatMap() : map + flatten
function* pairs(n) {
  yield n;
  yield n * 10;
}

const flattened = [1, 2, 3].values()
  .flatMap(n => pairs(n));
console.log([...flattened]); // [1, 10, 2, 20, 3, 30]

Chaînage Fluide

// Combiner des méthodes
const result = infiniteNumbers()
  .drop(10)           // Saute les 10 premiers
  .filter(n => n % 3 === 0)  // Seulement les multiples de 3
  .map(n => n ** 2)   // Élève au carré
  .take(5);           // Prend 5 résultats

console.log([...result]); // [144, 225, 324, 441, 576]

// Exemple pratique : traitement de données
function* readLines(text) {
  for (const line of text.split('\n')) {
    yield line;
  }
}

const logData = `
2025-01-01 ERROR: Connection failed
2025-01-01 INFO: Server started
2025-01-02 ERROR: Timeout
2025-01-02 INFO: Request processed
2025-01-03 ERROR: Invalid input
`;

const errors = readLines(logData)
  .filter(line => line.includes('ERROR'))
  .map(line => line.split('ERROR:')[1]?.trim())
  .filter(msg => msg);

console.log([...errors]);
// ['Connection failed', 'Timeout', 'Invalid input']

Compatibilité et Support

Avant d'utiliser ces fonctionnalités en production, vérifiez le support :

État d'Implémentation

Fonctionnalité Chrome Firefox Safari Node.js
Promise.try 128+ 132+ 18.2+ 22+
Float16Array 128+ En dev 18.2+ 22+
Duplicate Groups 125+ 129+ 18+ 21+
RegExp.escape 130+ 134+ En dev 23+
Set methods 122+ 127+ 17+ 22+
Iterator helpers 122+ 131+ 17+ 22+

Polyfills et Transpilation

// Pour les environnements qui ne supportent pas, utilisez core-js
import 'core-js/actual/promise/try';
import 'core-js/actual/set';
import 'core-js/actual/iterator';

// Ou configurez babel avec preset-env
// babel.config.js
module.exports = {
  presets: [
    ['@babel/preset-env', {
      targets: '> 0.25%, not dead',
      useBuiltIns: 'usage',
      corejs: 3
    }]
  ]
};

Conclusion

ECMAScript 2025 apporte des améliorations pratiques qui résolvent de vrais problèmes du quotidien. Promise.try() simplifie le traitement des erreurs, Float16Array ouvre les portes aux graphiques et au ML, et les nouvelles méthodes de Set et Iterator rendent les opérations courantes plus élégantes.

JavaScript continue d'évoluer de façon consistante, ajoutant des fonctionnalités qui nécessitaient auparavant des bibliothèques externes ou du code boilerplate. Se maintenir à jour avec ces nouveautés est essentiel pour écrire du code plus propre et efficace.

Si vous voulez approfondir JavaScript moderne, je recommande de jeter un œil à un autre article : Découvrir la Puissance de l'Async/Await en JavaScript où vous découvrirez comment maîtriser la programmation asynchrone.

C'est parti ! 🦅

Commentaires (0)

Cet article n'a pas encore de commentaires. Soyez le premier!

Ajouter des commentaires