Développement Web

Les nouveautes d’ECMAScript 2025 (ES2025) en pratique

14 دقائق للقراءة

📍 Le guide du parcours : JavaScript moderne : le guide complet

Sixième et dernier tutoriel de la série JavaScript moderne. Il modernise l’application construite tout au long du parcours.

Introduction

Le 25 juin 2025, Ecma International a approuvé ECMAScript 2025, la 16e édition de la norme du langage. Cette livraison apporte des outils qu’on attendait depuis des années : des opérations d’ensembles sur Set, des assistants paresseux sur les itérateurs, Promise.try, l’import direct de fichiers JSON, sans oublier la toute récente RegExp.escape. Aucune n’est gadget : chacune simplifie du code que vous écriviez jusqu’ici à la main. Dans ce tutoriel, vous allez les appliquer pour moderniser CarnetTâches, et repartir avec une idée claire de quoi adopter dès maintenant et comment vérifier la disponibilité de chaque fonctionnalité.

🎯 Ce que vous allez apprendre

  • Combiner et comparer des ensembles avec les nouvelles méthodes de Set.
  • Filtrer et transformer paresseusement avec les assistants d’itérateurs.
  • Unifier le traitement des erreurs synchrones et asynchrones avec Promise.try.
  • Importer un fichier JSON comme un module grâce aux attributs d’import.
  • Sécuriser une recherche par expression régulière avec RegExp.escape.
  • Savoir où vérifier la compatibilité de chaque nouveauté avant de l’utiliser en production.

🛠️ Ce que vous allez construire

Vous allez réécrire plusieurs morceaux de CarnetTâches avec ES2025 : la déduplication et le filtrage des étiquettes via les méthodes de Set, un pipeline de filtrage paresseux sur les tâches, un appel robuste avec Promise.try, le chargement de la configuration depuis un fichier JSON, et une recherche par motif sûre. Chaque exemple remplace un code plus verbeux écrit aux tutoriels précédents.

Prérequis

  • Un navigateur récent et, pour les modules JSON, Node 22 ou plus récent (au moment d’écrire, la version 24 est en support long terme actif). Aucune installation lourde.
  • Avoir suivi le parcours, ou maîtriser Set, les itérateurs, les promesses et les modules. Test express : si vous savez ce que fait new Set([1, 1, 2]), vous êtes prêt.
  • ⏱️ Temps estimé : ~45 minutes.

Étape 1 — Les méthodes de Set

Un Set est une collection de valeurs uniques. Jusqu’à ES2025, combiner deux ensembles (union, intersection, différence) imposait des boucles ou des conversions en tableaux. ES2025 ajoute sept méthodes directement sur Set.prototype : union, intersection, difference, symmetricDifference, isSubsetOf, isSupersetOf et isDisjointFrom. Appliquons-les aux étiquettes de CarnetTâches.

const etiquettesTache = new Set(["étude", "javascript", "urgent"]);
const etiquettesConnues = new Set(["étude", "lecture", "javascript", "loisir"]);

// Étiquettes de la tâche qui existent déjà dans le référentiel
const communes = etiquettesTache.intersection(etiquettesConnues);
console.log([...communes]);          // ["étude", "javascript"]

// Étiquettes nouvelles, à ajouter au référentiel
const nouvelles = etiquettesTache.difference(etiquettesConnues);
console.log([...nouvelles]);         // ["urgent"]

// Référentiel enrichi
const toutes = etiquettesConnues.union(etiquettesTache);
console.log([...toutes].length);     // 5 : doublons éliminés automatiquement

console.log(etiquettesTache.isSubsetOf(toutes));  // true

Ces méthodes prennent un autre ensemble (ou un objet « ensemble-compatible ») et renvoient un nouveau Set, sans modifier les originaux. Là où il fallait auparavant [...a].filter(x => b.has(x)) pour une intersection, on écrit a.intersection(b) — plus lisible et plus rapide. Pour la gestion des étiquettes, c’est exactement l’outil qu’on bricolait jusqu’ici.

Point d’étape — Tapez etiquettesTache.difference(etiquettesConnues) et inspectez le résultat avec [...]. Vous devez obtenir ["urgent"]. Si la méthode est undefined, votre environnement n’implémente pas encore les méthodes de Set — voyez l’étape sur la compatibilité.

Étape 2 — Les assistants d’itérateurs

Les méthodes de tableau map et filter créent un nouveau tableau complet à chaque appel : enchaîner filter().map().slice() alloue plusieurs tableaux intermédiaires. ES2025 introduit les mêmes opérations sur les itérateurs, mais de façon paresseuse : rien n’est calculé tant qu’on ne consomme pas le résultat, et seuls les éléments nécessaires sont traités. Idéal pour « prendre les trois premières tâches urgentes » sans parcourir toute la liste.

const taches = [
  { titre: "Réviser", priorite: 1, fait: false },
  { titre: "Courses", priorite: 3, fait: true },
  { titre: "Doc", priorite: 1, fait: false },
  { titre: "Sport", priorite: 1, fait: false },
  { titre: "Mail", priorite: 2, fait: false }
];

const deuxUrgentes = taches
  .values()                                   // itérateur sur le tableau
  .filter(t => t.priorite === 1 && !t.fait)   // paresseux : pas encore exécuté
  .map(t => t.titre)
  .take(2)                                     // s'arrête dès 2 éléments trouvés
  .toArray();                                  // consomme et matérialise

console.log(deuxUrgentes);                     // ["Réviser", "Doc"]

La chaîne ne fait rien jusqu’à toArray(), qui déclenche l’évaluation. Grâce à take(2), le moteur s’arrête dès qu’il a deux résultats : « Sport » et « Mail » ne sont jamais examinés. Les assistants disponibles reprennent les noms connus — map, filter, take, drop, flatMap, reduce, some, every, find, forEach, toArray — mais s’appliquent à tout itérateur, y compris ceux de taille inconnue ou infinie.

Étape 3 — Promise.try

Vous avez une fonction qui peut être synchrone ou asynchrone, et qui peut lever une erreur dès son appel (avant même de renvoyer une promesse). Avant ES2025, unifier ces cas demandait un try/catch autour de l’appel plus un .catch() sur la promesse. Promise.try exécute la fonction et enveloppe tout — valeur de retour, promesse, ou exception synchrone — dans une seule promesse. Un seul .catch() suffit alors.

function chargerConfig(source) {
  if (!source) throw new Error("source manquante");   // erreur SYNCHRONE
  return fetch(source).then(r => r.json());            // sinon, promesse
}

// Promise.try attrape l'erreur synchrone ET les rejets asynchrones, d'un seul bloc
Promise.try(() => chargerConfig(""))      // ici, lève tout de suite
  .then(config => console.log("Config :", config))
  .catch(e => console.error("Échec unifié :", e.message));  // "source manquante"

// Cas nominal
Promise.try(() => chargerConfig("https://jsonplaceholder.typicode.com/todos/1"))
  .then(config => console.log("Reçu :", config))
  .catch(e => console.error(e.message));

Sans Promise.try, l’appel chargerConfig("") lèverait son erreur de façon synchrone, hors de la chaîne de promesses, et le .catch() ne l’attraperait pas. Promise.try garantit que toute issue de la fonction — succès immédiat, promesse, ou exception levée tout de suite — passe par le même canal. C’est un petit confort qui élimine une classe entière de bugs sournois.

Point d’étape — Le premier appel doit afficher « Échec unifié : source manquante » via le .catch(), alors que l’erreur est levée de façon synchrone. C’est la preuve que Promise.try capture aussi les exceptions immédiates.

Étape 4 — Les modules JSON et les attributs d’import

Charger un fichier de configuration JSON imposait jusqu’ici un fetch et un response.json(). ES2025 standardise l’import direct d’un fichier JSON comme module, à condition de préciser son type avec un attribut d’import — la syntaxe with { type: "json" }. C’est plus déclaratif et résolu au chargement.

// config.json
{
  "titre": "CarnetTâches",
  "prioriteParDefaut": 2,
  "etiquettesSuggerees": ["étude", "travail", "loisir"]
}
// import statique d'un module JSON (l'attribut de type est obligatoire)
import config from "./config.json" with { type: "json" };

console.log(config.titre);                 // "CarnetTâches"
console.log(config.prioriteParDefaut);     // 2

// variante dynamique, à la demande
const { default: cfg } = await import("./config.json", { with: { type: "json" } });
console.log(cfg.etiquettesSuggerees);      // ["étude", "travail", "loisir"]

L’attribut with { type: "json" } n’est pas optionnel : il indique au moteur comment interpréter le fichier, et c’est aussi une mesure de sécurité (le contenu ne sera jamais exécuté comme du code). En version dynamique, l’option passe dans un objet { with: { type: "json" } }. Côté Node.js, l’import de modules JSON est disponible sur les versions récentes ; vérifiez votre version, car le détail de la syntaxe a évolué avant sa stabilisation.

Étape 5 — RegExp.escape pour une recherche sûre

Souvenez-vous de la recherche du tutoriel sur le DOM. Si l’on veut filtrer les tâches localement avec une expression régulière construite à partir du terme saisi, un problème surgit : si l’utilisateur tape "c++" ou "prix (€)", ces caractères ont une signification spéciale en regex et cassent le motif, voire ouvrent une faille. RegExp.escape, une addition très récente du langage, échappe proprement une chaîne pour l’insérer sans risque dans une expression régulière.

function filtrerParTerme(taches, terme) {
  // RegExp.escape neutralise les caractères spéciaux du terme saisi
  const motif = new RegExp(RegExp.escape(terme), "i");  // "i" = insensible à la casse
  return taches.filter(t => motif.test(t.titre));
}

const taches = [
  { titre: "Réviser C++" },
  { titre: "Acheter (lait)" },
  { titre: "Lire la doc" }
];

console.log(filtrerParTerme(taches, "c++").length);     // 1 — pas d'erreur de motif
console.log(filtrerParTerme(taches, "(lait)").length);  // 1 — parenthèses traitées comme texte

Sans RegExp.escape, new RegExp("c++") lèverait une erreur de syntaxe (le + attend quelque chose à répéter), et "(lait)" serait interprété comme un groupe de capture. La méthode transforme ces caractères en littéraux, ce qui rend la recherche fiable quelle que soit la saisie. C’est exactement le genre de détail qui distingue un code de démonstration d’un code prêt à affronter de vrais utilisateurs.

Point d’étape — Sans RegExp.escape, new RegExp("c++") lève SyntaxError: Invalid regular expression. Avec, la recherche fonctionne. Testez les deux dans la console pour mesurer la différence.

Étape 6 — Les autres apports d’ES2025

Trois ajouts plus spécialisés méritent d’être connus, même si on les croise moins souvent. Ils complètent le tableau de ce que la 16e édition standardise.

D’abord, les groupes de capture nommés dupliqués dans les expressions régulières : on peut réutiliser le même nom de groupe dans des branches alternatives d’un motif, ce qui était interdit auparavant. Ensuite, Float16Array, un nouveau tableau typé pour les flottants demi-précision (16 bits), utile en calcul graphique et en apprentissage automatique où la mémoire compte ; il s’accompagne des méthodes getFloat16 et setFloat16 sur DataView. Enfin, les modificateurs en ligne dans les expressions régulières, qui permettent d’activer un drapeau (comme l’insensibilité à la casse) sur une portion seulement d’un motif.

// Groupes nommés dupliqués : même nom "annee" dans deux branches alternatives
const motif = /(?<annee>\d{4})-\d{2}|(?<annee>\d{2})\/\d{4}/;
console.log("2026-06".match(motif).groups.annee);   // "2026"

// Modificateur en ligne : insensible à la casse SEULEMENT sur "todo"
const r = /(?i:todo):\s\d+/;
console.log(r.test("TODO: 5"));   // true — le "i:" ne s'applique qu'au groupe

Vous n’aurez pas besoin de ces fonctionnalités tous les jours, mais les reconnaître évite la surprise quand vous les croiserez dans le code d’autrui. Float16Array en particulier signale un usage pointu (traitement de données numériques volumineuses) plutôt qu’une application de gestion classique comme la nôtre.

Étape 7 — Vérifier la compatibilité avant d’adopter

Une fonctionnalité standardisée n’est pas instantanément partout. Les navigateurs et Node l’implémentent à leur rythme, et la plupart de ces nouveautés ont commencé à apparaître courant 2024-2025. Avant d’utiliser l’une d’elles en production, vérifiez sa disponibilité dans vos cibles. La démarche est systématique et ne prend qu’une minute.

// Détection de fonctionnalité : tester avant d'utiliser
const aSetMethods = typeof Set.prototype.union === "function";
const aPromiseTry = typeof Promise.try === "function";
const aRegExpEscape = typeof RegExp.escape === "function";

console.log({ aSetMethods, aPromiseTry, aRegExpEscape });

if (!aSetMethods) {
  console.warn("Méthodes de Set absentes : prévoir un repli ou mettre à jour le moteur.");
}

Pour une vérification fiable et à jour, deux sources font autorité : les pages MDN de chaque fonctionnalité (section « Compatibilité des navigateurs ») et le tableau de bord caniuse. Côté serveur, le calendrier des versions de Node.js indique ce que prend en charge chaque ligne — au moment d’écrire, Node 24 est la version de support long terme active et la 22 reste maintenue. Quand une cible ne suit pas encore, deux options : remonter la version du moteur, ou prévoir un repli (le code « à l’ancienne » que ces nouveautés remplacent).

🐞 Pièges fréquents

Symptôme / erreur Cause probable Correctif
set.union is not a function Moteur trop ancien pour les méthodes de Set Mettre à jour, ou repli via tableaux
La chaîne d’itérateurs ne renvoie rien Oubli du terminal toArray() (évaluation paresseuse) Consommer l’itérateur (toArray, forEach…)
Une erreur synchrone échappe au .catch() Appel hors d’une chaîne de promesses Envelopper avec Promise.try
import ... with { type: "json" } rejeté Attribut de type manquant ou version trop ancienne Préciser le type ; vérifier la version de Node
SyntaxError en construisant une regex Caractères spéciaux non échappés dans le terme Passer le terme par RegExp.escape

🌍 Réalités du terrain

Adopter ES2025 demande une attention particulière à l’environnement d’exécution, surtout quand on ne maîtrise pas le navigateur de l’utilisateur final. La règle est simple : tester la disponibilité (comme à l’étape 7) et prévoir un repli pour les moteurs en retard. Bonne nouvelle, ces nouveautés n’alourdissent rien — ce sont des capacités natives, sans dépendance à télécharger, donc sans coût de bande passante. Sur le serveur, où vous choisissez la version de Node, vous pouvez les utiliser sans réserve dès lors que votre version les prend en charge. Quand vous devez viser de vieux navigateurs, les outils de transpilation reproduisent ces fonctionnalités, mais commencez toujours par mesurer si c’est réellement nécessaire pour votre public.

✅ Récapitulatif

Vous connaissez désormais les apports majeurs d’ECMAScript 2025 et vous les avez appliqués à CarnetTâches : méthodes de Set pour les étiquettes, assistants d’itérateurs pour un filtrage paresseux, Promise.try pour unifier les erreurs, modules JSON via les attributs d’import, et RegExp.escape pour une recherche sûre. Vous avez aussi vu les ajouts plus spécialisés (groupes nommés dupliqués, Float16Array, modificateurs en ligne) et, surtout, la démarche pour vérifier la compatibilité avant d’adopter. Votre parcours JavaScript moderne est complet, de la valeur de base aux fonctionnalités les plus récentes.

🧾 Aide-mémoire

Élément Rôle
a.union(b), a.intersection(b) Opérations d’ensembles sur Set
iter.filter(fn).take(n).toArray() Assistants d’itérateurs (paresseux)
Promise.try(fn) Enveloppe sync/async/exception dans une promesse
import x from "./f.json" with { type: "json" } Module JSON via attribut d’import
RegExp.escape(str) Échappe une chaîne pour un usage en regex
Float16Array Tableau typé flottant demi-précision
typeof Set.prototype.union === "function" Détection de fonctionnalité avant usage

💪 À vous de jouer

Réécrivez la déduplication des étiquettes de toutes les tâches en une ligne, en combinant les méthodes de Set et les assistants d’itérateurs, pour obtenir l’ensemble unique de toutes les étiquettes utilisées.

Voir une solution
const taches = [
  { titre: "A", etiquettes: ["étude", "urgent"] },
  { titre: "B", etiquettes: ["lecture", "étude"] },
  { titre: "C", etiquettes: ["urgent"] }
];

// flatMap paresseux sur l'itérateur, puis Set pour l'unicité
const toutesEtiquettes = new Set(
  taches.values().flatMap(t => t.etiquettes.values()).toArray()
);

console.log([...toutesEtiquettes]);   // ["étude", "urgent", "lecture"]
console.log(toutesEtiquettes.size);   // 3

Tutoriels liés

Pour aller plus loin

FAQ

Puis-je utiliser ces fonctionnalités dès aujourd’hui ?
Côté serveur, oui, dès que votre version de Node les prend en charge — vous contrôlez l’environnement. Côté navigateur, vérifiez la compatibilité de chaque fonctionnalité sur MDN ou caniuse, car le déploiement s’est étalé sur 2024-2025 et certains utilisateurs ont des versions plus anciennes.

Quelle différence entre les assistants d’itérateurs et map/filter de tableau ?
Les méthodes de tableau créent un nouveau tableau complet à chaque étape. Les assistants d’itérateurs sont paresseux : ils ne calculent que ce qui est consommé, ce qui économise de la mémoire et permet de s’arrêter tôt (avec take), y compris sur des séquences infinies.

Le Temporal API fait-il partie d’ES2025 ?
Non. Temporal, qui modernise la gestion des dates, suit son propre calendrier et n’est pas inclus dans l’édition 2025. Ne le confondez pas avec les fonctionnalités décrites ici.

Dois-je remplacer tout mon ancien code par ces nouveautés ?
Non, par pragmatisme. Adoptez-les sur le nouveau code et lors des refactorisations, là où elles clarifient réellement. Inutile de réécrire du code qui fonctionne uniquement pour utiliser la dernière syntaxe.

مشاركة