À propos de ce cours
Cette leçon fait le point sur ECMAScript, la norme qui définit JavaScript : la différence entre la norme et le langage, le rôle d'Ecma International et du comité TC39, et pourquoi ce rappel est indispensable avant Angular, puisque TypeScript ajoute seulement les types et les décorateurs à ECMAScript. Un tableau et une frise chronologique présentent les versions d'ES5 à ES2026, approuvée le 30 juin 2026. Chaque nouveauté est illustrée par un exemple : let et const, fonctions fléchées et this, gabarits ${}, déstructuration, spread et rest, paramètres par défaut, classes (extends, super, static, champs privés #), modules import / export, méthodes de tableaux de map à Object.groupBy, chaînage optionnel ?. et opérateur ??, Map et Set, promesses et async / await. Huit activités pratiques permettent de s'exercer avec Node.js.
-
Objectifs
- Savoir ce qu'est ECMAScript et le distinguer de JavaScript
- Connaître les principales versions de la norme, d'ES5 aux versions annuelles récentes
- Utiliser les nouveautés d'ES6 et suivantes :
let/const, fonctions fléchées, gabarits de chaînes, déstructuration, spread / rest, classes, modules - Manipuler les tableaux et les objets avec les méthodes modernes (
map,filter,reduce,find,at,toSorted…) - Utiliser le chaînage optionnel
?.et l'opérateur?? - Écrire du code asynchrone avec les promesses et
async/await - Reconnaître ces notions dans le code d'une application Angular
-
Présentation
- ECMAScript (abrégé ES) est la norme qui définit le langage JavaScript : sa syntaxe, ses types, ses mots-clés et ses objets de base (
Array,Object,Promise…). Son nom officiel est ECMA-262. - JavaScript est l'implémentation la plus connue de cette norme : les moteurs V8 (Chrome, Edge, Node.js), SpiderMonkey (Firefox) et JavaScriptCore (Safari) appliquent ECMAScript.
- La norme est publiée par l'organisme Ecma International. Les nouveautés sont proposées et validées par le comité TC39, qui réunit les éditeurs de navigateurs et de grandes entreprises du Web.
- Une analogie : ECMAScript est la recette, JavaScript est le plat préparé par chaque navigateur en suivant cette recette.
- Pourquoi ce rappel avant Angular ? Angular s'écrit en TypeScript, qui est un sur-ensemble d'ECMAScript : TypeScript ajoute les types et les décorateurs, mais tout le reste (classes, modules, fonctions fléchées, déstructuration,
async/await…) est de l'ECMAScript moderne. Sans ces bases, le code Angular est très difficile à lire.
- ECMAScript (abrégé ES) est la norme qui définit le langage JavaScript : sa syntaxe, ses types, ses mots-clés et ses objets de base (

-
Les versions d'ECMAScript
- Jusqu'en 2015, les versions étaient numérotées (ES3, ES5…) et espacées de plusieurs années. ES6, sortie en 2015 sous le nom officiel ES2015, a profondément modernisé le langage.
- Depuis, une nouvelle version sort chaque année, en juin, et porte le nom de son année : ES2016, ES2017… Chaque version ajoute quelques nouveautés. Une proposition passe par plusieurs stades (de 0 à 4) au TC39 avant d'être intégrée à la norme.
- On parle souvent d'« ES6+ » pour désigner l'ensemble des nouveautés apparues depuis 2015 : c'est le JavaScript moderne.
| Version | Année | Principales nouveautés |
|---|---|---|
| ES5 | 2009 | mode strict ('use strict'), forEach, map, filter, reduce, JSON |
| ES6 / ES2015 | 2015 | let et const, fonctions fléchées, classes, modules, gabarits de chaînes, déstructuration, spread et rest, paramètres par défaut, promesses, Map et Set, for…of |
| ES2016 | 2016 | Array.prototype.includes(), opérateur puissance ** |
| ES2017 | 2017 | async / await, Object.entries(), Object.values(), padStart() |
| ES2018 | 2018 | spread et rest sur les objets, Promise.finally() |
| ES2019 | 2019 | flat(), flatMap(), Object.fromEntries() |
| ES2020 | 2020 | chaînage optionnel ?., coalescence des nuls ??, BigInt, Promise.allSettled() |
| ES2021 | 2021 | ??=, ||=, &&=, replaceAll(), séparateur numérique 1_000_000 |
| ES2022 | 2022 | champs et méthodes privés #, champs static, at(), await au niveau supérieur d'un module |
| ES2023 | 2023 | toSorted(), toReversed(), findLast(): méthodes qui ne modifient pas le tableau d'origine |
| ES2024 | 2024 | Object.groupBy(), Promise.withResolvers() |
| ES2025 | 2025 | méthodes des ensembles (union, intersection, difference…), assistants d'itérateurs, Promise.try() |
| ES2026 | 2026 | Math.sumPrecise(), Error.isError(), Array.fromAsync(), Iterator.concat()… |
- Retenir surtout ES6 (2015) : la très grande majorité des notions utilisées chaque jour dans Angular datent de cette version. Les versions suivantes apportent des améliorations pratiques, dont plusieurs sont présentées dans cette leçon.
Préparer l'environnement de test
- Tous les exemples de cette leçon s'exécutent avec Node.js, sans navigateur (voir Présentation de l'environnement de développement Node.js) :
- un fichier
.jss'exécute avecnode nom-du-fichier.js; - un fichier qui utilise
import/exportporte l'extension.mjs(module ES) et s'exécute de la même façon :node nom-du-fichier.mjs.
- un fichier
- On peut aussi tester une ligne rapidement dans la console du navigateur (F12, onglet Console) ou dans la console interactive de Node (
node, puis.exitpour quitter).
Activité 1 : préparer le dossier et le dépôt GitHub
- Créer un dépôt vide
rappel-ecmascriptsur GitHub (sans README). - Créer le dossier du même nom, l'ouvrir dans VS Code et initialiser Git :
mkdir rappel-ecmascript
cd rappel-ecmascript
git init
code .
- Créer un fichier
00-test.jscontenantconsole.log('ECMAScript avec Node.js', process.version);et l'exécuter avecnode 00-test.js. - Faire le premier commit et l'envoyer sur GitHub :
git add .
git commit -m "Activité 1 : préparation du dossier"
git branch -M main
git remote add origin https://github.com/VOTRE-COMPTE/rappel-ecmascript.git
git push -u origin main
- Règle de la leçon : chaque activité est écrite dans un fichier numéroté (
02-portee.js,03-fiche.js…) et se termine par un commit et un push.
let et const : déclarer des variables
- Avant ES6, on déclarait toutes les variables avec
var. ES6 introduitletetconst, qui corrigent ses défauts. constdéclare une variable qu'on ne peut pas réaffecter. C'est le choix par défaut.letdéclare une variable qu'on peut réaffecter (un compteur, un total qui évolue…).varest à éviter : sa portée est la fonction entière, pas le bloc{ }, ce qui provoque des erreurs difficiles à trouver.
var |
let |
const |
|
|---|---|---|---|
| Portée | la fonction | le bloc { } |
le bloc { } |
| Réaffectation | oui | oui | non |
| Utilisation avant la déclaration | vaut undefined |
erreur ReferenceError |
erreur ReferenceError |
| Redéclaration dans la même portée | autorisée | interdite | interdite |
const tauxTVA = 0.19;
// tauxTVA = 0.07; // TypeError: Assignment to constant variable.
let total = 0;
total = total + 50; // autorisé avec let
// const empêche la réaffectation, pas la modification du contenu
const stagiaire = { nom: 'Sami' };
stagiaire.nom = 'Amira'; // autorisé : on modifie une propriété
console.log(stagiaire); // { nom: 'Amira' }
// stagiaire = { nom: 'Karim' }; // interdit : réaffectation
- Exemple : la portée de
varet deletdans une boucle
for (var i = 0; i < 3; i++) {
setTimeout(() => console.log('var', i), 0);
}
for (let j = 0; j < 3; j++) {
setTimeout(() => console.log('let', j), 0);
}
// Résultat :
// var 3 var 3 var 3 → une seule variable i, partagée
// let 0 let 1 let 2 → une nouvelle variable j à chaque tour
- Règle simple : utilisez
constpartout ; remplacez-le parletseulement si VS Code ou Node signale que la variable doit être réaffectée. N'utilisez plusvar.
Activité 2 : prédire avant d'exécuter
- Dans
02-portee.js, recopier le code ci-dessous. Avant de l'exécuter, écrire en commentaire ce que vous pensez qu'il affiche. Exécuter, puis comparer et expliquer chaque différence en commentaire.
console.log(a); // ?
var a = 3;
try {
console.log(b); // ?
let b = 3;
} catch (e) {
console.log(e.name + ' : ' + e.message);
}
const formation = { titre: 'Web', places: 10 };
formation.places--;
console.log(formation.places); // ?
if (true) {
var x = 'var';
let y = 'let';
}
console.log(x); // ?
console.log(typeof y); // ?
-
Les fonctions fléchées
- Une fonction fléchée (arrow function) est une écriture courte d'une fonction, avec la flèche
=>.
- Une fonction fléchée (arrow function) est une écriture courte d'une fonction, avec la flèche
// Fonction classique
function carre(n) {
return n * n;
}
// Fonction fléchée équivalente
const carreFlechee = (n) => n * n; // une seule expression : return implicite
const saluer = () => 'Bonjour'; // aucun paramètre : parenthèses vides
const addition = (a, b) => a + b; // plusieurs paramètres
const moyenne = (notes) => { // plusieurs instructions : accolades + return
const somme = notes.reduce((s, n) => s + n, 0);
return somme / notes.length;
};
const creerStagiaire = (nom) => ({ nom, actif: true }); // renvoyer un objet : parenthèses autour
console.log(carreFlechee(4), saluer(), addition(2, 3), moyenne([10, 14, 18]));
- Différence importante : une fonction fléchée n'a pas son propre
this. Elle utilise lethisde l'endroit où elle est écrite. C'est très pratique dans les classes Angular, notamment dans les fonctions de rappel (callbacks).
const compteur = {
valeur: 0,
demarrerClassique() {
setTimeout(function () {
console.log('classique :', this === compteur); // false : this a changé
}, 0);
},
demarrerFlechee() {
setTimeout(() => {
this.valeur++; // this = compteur
console.log('fléchée :', this.valeur); // 1
}, 0);
},
};
compteur.demarrerClassique();
compteur.demarrerFlechee();
-
Les gabarits de chaînes (template literals)
- Un gabarit s'écrit entre accents graves
` `(Alt Gr + 7 sur un clavier AZERTY). On y insère des expressions avec${ }, et il peut s'étendre sur plusieurs lignes.
- Un gabarit s'écrit entre accents graves
const nom = 'Amira';
const moyenne = 15.456;
// Avant ES6 : concaténation
console.log('Bonjour ' + nom + ', votre moyenne est ' + moyenne.toFixed(2) + ' / 20.');
// Avec un gabarit
console.log(`Bonjour ${nom}, votre moyenne est ${moyenne.toFixed(2)} / 20.`);
// Sur plusieurs lignes, avec une expression
const carte = `
<div class="card">
<h5>${nom.toUpperCase()}</h5>
<p>${moyenne >= 10 ? 'Admis' : 'Ajourné'}</p>
</div>`;
console.log(carte);
- Dans Angular : on retrouve les accents graves dans la propriété
templated'un composant (HTML écrit dans le fichier.ts). Attention à ne pas confondre${ }(JavaScript) et{{ }}(interpolation Angular dans un template).
La déstructuration
- La déstructuration extrait des valeurs d'un objet ou d'un tableau et les range dans des variables, en une seule instruction.
// Objet
const formation = { titre: 'Développement web', duree: 24, niveau: 'BTS', lieu: { ville: 'Tunis' } };
const { titre, niveau } = formation; // mêmes noms que les propriétés
const { duree: dureeMois } = formation; // renommer : dureeMois = 24
const { salle = 'A1' } = formation; // valeur par défaut si absente
const { lieu: { ville } } = formation; // objet imbriqué : ville = 'Tunis'
console.log(titre, niveau, dureeMois, salle, ville);
// Tableau : la position compte
const modules = ['HTML', 'CSS', 'JS', 'TS', 'Angular'];
const [premier, , troisieme, ...reste] = modules; // on saute le 2e élément
console.log(premier, troisieme, reste); // HTML JS [ 'TS', 'Angular' ]
// Échanger deux variables
let a = 1, b = 2;
[a, b] = [b, a];
console.log(a, b); // 2 1
// Dans les paramètres d'une fonction
const presenter = ({ titre, duree }) => `${titre} (${duree} mois)`;
console.log(presenter(formation));
-
Spread, rest, paramètres par défaut et raccourcis
- Les trois points
...ont deux rôles selon l'endroit où ils sont écrits :- spread (étalement) : déplie un tableau ou un objet ;
- rest (reste) : regroupe plusieurs valeurs dans un tableau.
- Les trois points
// Spread sur un tableau
const notes = [12, 15, 9];
console.log(Math.max(...notes)); // 15 : comme Math.max(12, 15, 9)
const copie = [...notes, 18]; // nouveau tableau, l'original ne change pas
console.log(copie, notes); // [ 12, 15, 9, 18 ] [ 12, 15, 9 ]
// Spread sur un objet (ES2018) : copier puis modifier
const base = { nom: 'Sami', groupe: 'DEV1' };
const misAJour = { ...base, groupe: 'DEV2', actif: true };
console.log(misAJour); // { nom: 'Sami', groupe: 'DEV2', actif: true }
// Rest dans les paramètres : nombre de valeurs libre
function moyenneDe(...valeurs) {
return valeurs.reduce((s, v) => s + v, 0) / valeurs.length;
}
console.log(moyenneDe(10, 14, 18)); // 14
// Paramètres par défaut
function saluer(nom = 'stagiaire', formule = 'Bonjour') {
return `${formule} ${nom}`;
}
console.log(saluer(), saluer('Amira'), saluer(undefined, 'Salut'));
// Raccourcis d'objets : propriété et méthode
const groupe = 'DEV1', effectif = 24;
const classe = {
groupe, // au lieu de groupe: groupe
effectif,
afficher() { // au lieu de afficher: function () { … }
return `${this.groupe} (${this.effectif})`;
},
};
console.log(classe.afficher());
- Dans Angular : on écrit
this.produits = [...this.produits, nouveau];plutôt quethis.produits.push(nouveau);. Créer un nouveau tableau permet à Angular de détecter le changement de façon fiable : c'est le principe d'immutabilité.
Activité 3 : la fiche du stagiaire
- Dans
03-fiche.js, écrire une fonction fléchéecreerFichequi :- reçoit un objet stagiaire et le déstructure dans ses paramètres (
nom,prenom,groupeavec la valeur par défaut'Non affecté',notesavec la valeur par défaut[]) ; - reçoit ensuite un nombre libre d'options grâce au paramètre rest;
- calcule la moyenne (0 si aucune note) et renvoie la fiche avec un gabarit, le nom en majuscules.
- reçoit un objet stagiaire et le déstructure dans ses paramètres (
- Tester avec le code suivant ; le résultat doit être exactement celui indiqué :
console.log(creerFiche({ nom: 'Ben Ali', prenom: 'Amira', groupe: 'DEV1', notes: [14, 16, 17] }));
console.log(creerFiche({ nom: 'Trabelsi', prenom: 'Sami' }, 'boursier', 'délégué'));
// Résultat attendu :
// Amira BEN ALI – DEV1 – moyenne : 15.67
// Sami TRABELSI – Non affecté – moyenne : 0.00 – boursier, délégué
-
Les classes
- ES6 introduit le mot-clé
classpour écrire des objets « modèles » de façon claire. Toutes les briques Angular sont des classes : composants, services, pipes, directives.
- ES6 introduit le mot-clé
class Personne {
static nombre = 0; // champ statique (ES2022) : partagé par la classe
#cin; // champ privé (ES2022) : invisible hors de la classe
constructor(nom, cin) { // appelé par new
this.nom = nom;
this.#cin = cin;
Personne.nombre++;
}
get initiale() { // accesseur : s'utilise comme une propriété
return this.nom[0];
}
presenter() { // méthode
return `Je suis ${this.nom}`;
}
}
class Stagiaire extends Personne { // héritage
constructor(nom, cin, groupe) {
super(nom, cin); // appelle le constructeur parent
this.groupe = groupe;
}
presenter() { // redéfinition
return `${super.presenter()}, stagiaire en ${this.groupe}`;
}
}
const s = new Stagiaire('Amira', '01234567', 'DEV1');
console.log(s.presenter()); // Je suis Amira, stagiaire en DEV1
console.log(s.initiale); // A
console.log(Personne.nombre); // 1
console.log(s.cin); // undefined : #cin est privé
- Remarque : en TypeScript, on rencontre aussi le mot-clé
private(vérifié seulement à la compilation), alors que#est une vraie protection d'ECMAScript, vérifiée à l'exécution.
Activité 4 : les classes Formation et FormationEnLigne
- Dans
04-classes.js, écrire :- une classe
Formationavec un champ statiquenombre, un champ privé#places, un constructeur(titre, dureeMois, places = 20), un accesseurplacesRestantes, une méthodeinscrire()qui diminue les places ou renvoie « complet », et une méthodepresenter(); - une classe
FormationEnLignequi hérite deFormation, fixe toujours 100 places, ajoute une propriétéplateformeet redéfinitpresenter()avecsuper.
- une classe
- Tester avec le code suivant :
const web = new Formation('Développement web', 24, 1);
const design = new FormationEnLigne('Infographie', 12, 'Moodle');
console.log(web.presenter());
console.log(design.presenter());
console.log(web.inscrire());
console.log(web.inscrire());
console.log(`Nombre de formations : ${Formation.nombre}`);
web.placesRestantes = 50; // tentative de modification
console.log(web.placesRestantes);
// Résultat attendu :
// Développement web – 24 mois
// Infographie – 12 mois – en ligne sur Moodle
// Développement web : inscription validée (0 places restantes)
// Développement web : complet
// Nombre de formations : 2
// 0
- Expliquer en commentaire pourquoi la dernière ligne affiche
0et non50.
Les modules : import et export
- Un module est un fichier qui exporte ce qu'il veut partager ; les autres fichiers l'importent. Chaque module a sa propre portée : ses variables ne « fuient » pas dans les autres fichiers.
- Il existe deux types d'export :
- export nommé: plusieurs par fichier, importés entre accolades avec le même nom ;
- export par défaut: un seul par fichier, importé sans accolades avec le nom de son choix.
// outils.mjs
export const TVA = 0.19;
export function prixTTC(prixHT) {
return +(prixHT * (1 + TVA)).toFixed(3);
}
export default class Panier {
#articles = [];
ajouter(article) {
this.#articles.push(article);
}
get total() {
return this.#articles.reduce((t, a) => t + prixTTC(a.prix), 0);
}
}
// index.mjs
import Panier, { prixTTC, TVA as tauxTVA } from './outils.mjs'; // défaut + nommés (dont un renommé)
import * as outils from './outils.mjs'; // tout le module dans un objet
console.log(prixTTC(100), tauxTVA, outils.TVA); // 119 0.19 0.19
const panier = new Panier();
panier.ajouter({ nom: 'Clavier', prix: 45 });
panier.ajouter({ nom: 'Souris', prix: 20 });
console.log(`Total TTC : ${panier.total.toFixed(3)} DT`); // Total TTC : 77.350 DT
- Dans Angular : le projet est un ensemble de modules ES. Chaque composant est une classe exportée (
export class Entete) puis importée là où on l'utilise (import { Entete } from './layout/entete/entete';). Les paquets installés avec npm s'importent par leur nom, sans chemin :import { Component } from '@angular/core';. Angular utilise presque toujours des exports nommés.
Les méthodes modernes des tableaux et des objets
- Ces méthodes remplacent la plupart des boucles
for. Elles reçoivent une fonction (souvent fléchée) appelée pour chaque élément. Exemple avec la liste suivante :
const stagiaires = [
{ nom: 'Amira', groupe: 'DEV1', moyenne: 15.5 },
{ nom: 'Sami', groupe: 'DEV2', moyenne: 9.75 },
{ nom: 'Yasmine', groupe: 'DEV1', moyenne: 12 },
{ nom: 'Karim', groupe: 'DEV2', moyenne: 17.25 },
];
| Méthode | Rôle | Exemple | Résultat |
|---|---|---|---|
map() |
transforme chaque élément → nouveau tableau | stagiaires.map(s => s.nom) |
['Amira', 'Sami', 'Yasmine', 'Karim'] |
filter() |
garde les éléments qui vérifient la condition | stagiaires.filter(s => s.moyenne >= 10).length |
3 |
find() |
renvoie le premier élément trouvé (ou undefined) |
stagiaires.find(s => s.nom === 'Sami').moyenne |
9.75 |
some() / every() |
au moins un / tous vérifient la condition | stagiaires.some(s => s.moyenne < 10) |
true |
reduce() |
réduit le tableau à une seule valeur | stagiaires.reduce((t, s) => t + s.moyenne, 0) |
54.5 |
includes() |
le tableau contient-il cette valeur ? | ['HTML', 'CSS'].includes('CSS') |
true |
at() |
élément à une position, négative depuis la fin | stagiaires.at(-1).nom |
'Karim' |
toSorted() |
copie triée, l'original ne change pas (≠ sort()) |
stagiaires.toSorted((a, b) => b.moyenne - a.moyenne)[0].nom |
'Karim' |
Object.groupBy() |
regroupe les éléments selon une clé | Object.groupBy(stagiaires, s => s.groupe).DEV1.length |
2 |
Object.entries() |
paires [clé, valeur] d'un objet |
Object.entries({ nom: 'Sami', groupe: 'DEV1' }) |
[['nom', 'Sami'], ['groupe', 'DEV1']] |
// Enchaîner les méthodes : noms des admis, du meilleur au moins bon
const admis = stagiaires
.filter((s) => s.moyenne >= 10)
.toSorted((a, b) => b.moyenne - a.moyenne)
.map((s) => `${s.nom} (${s.moyenne})`);
console.log(admis); // [ 'Karim (17.25)', 'Amira (15.5)', 'Yasmine (12)' ]
// Parcourir un objet avec for…of et la déstructuration
for (const [cle, valeur] of Object.entries({ nom: 'Sami', groupe: 'DEV1' })) {
console.log(`${cle} = ${valeur}`);
}
-
Chaînage optionnel ?. et coalescence des nuls ??
?.(ES2020) lit une propriété seulement si l'objet existe ; sinon il renvoieundefinedau lieu de provoquer une erreur.??(ES2020) donne une valeur de remplacement seulement si la valeur estnullouundefined. Contrairement à||, il garde les valeurs0,''etfalse.
const reponse = { stagiaire: { nom: 'Amira', adresse: null } };
// console.log(reponse.stagiaire.adresse.ville); // TypeError : adresse est null
console.log(reponse.stagiaire?.adresse?.ville); // undefined, sans erreur
console.log(reponse.formateur?.nom ?? 'non affecté'); // non affecté
// || ou ?? : la différence
console.log(0 || 20); // 20 : 0 est considéré comme « faux »
console.log(0 ?? 20); // 0 : 0 n'est ni null ni undefined
// ??= (ES2021) : affecter seulement si la valeur est absente
const options = {};
options.theme ??= 'clair';
console.log(options); // { theme: 'clair' }
- Dans Angular : on écrit souvent
{{ utilisateur?.nom ?? 'Invité' }}dans un template, pour afficher une donnée qui n'est pas encore chargée sans faire planter la page.
Map et Set
Setest une collection de valeurs uniques;Mapassocie des clés à des valeurs, avec des clés de n'importe quel type.
const langages = new Set(['JS', 'TS', 'JS']);
console.log(langages.size, [...langages]); // 2 [ 'JS', 'TS' ] : doublon supprimé
// Méthodes des ensembles (ES2025)
const front = new Set(['HTML', 'CSS', 'JS']);
const back = new Set(['PHP', 'JS']);
console.log([...front.union(back)]); // [ 'HTML', 'CSS', 'JS', 'PHP' ]
console.log([...front.intersection(back)]); // [ 'JS' ]
const notes = new Map([['Amira', 15.5]]);
notes.set('Sami', 9.75);
console.log(notes.get('Sami'), notes.size); // 9.75 2
-
La programmation asynchrone : promesses et async / await
- Une opération asynchrone prend du temps (appel à une API, lecture d'un fichier) : le programme continue sans l'attendre et traite le résultat plus tard.
- Une promesse (
Promise, ES6) représente ce résultat futur. Elle est soit tenue (resolve), soit rompue (reject). async/await(ES2017) permet d'écrire ce code comme s'il était séquentiel ; les erreurs se gèrent avectry/catch.
// async.mjs
function chargerStagiaire(id) {
return new Promise((resolve, reject) => {
setTimeout(() => { // simule une API qui répond en 1 seconde
if (id > 0) resolve({ id, nom: 'Amira', groupe: 'DEV1' });
else reject(new Error(`Stagiaire ${id} introuvable`));
}, 1000);
});
}
// 1) Avec then / catch / finally
console.log('1. Demande envoyée');
chargerStagiaire(1)
.then((s) => console.log('3. Reçu :', s.nom))
.catch((e) => console.error('Erreur :', e.message))
.finally(() => console.log('4. Terminé'));
console.log('2. Suite du programme');
// 2) Avec async / await
async function afficher(id) {
try {
const s = await chargerStagiaire(id);
console.log(`async/await : ${s.nom} (${s.groupe})`);
} catch (e) {
console.error('async/await, erreur :', e.message);
}
}
await afficher(1);
await afficher(-5);
// 3) Plusieurs promesses en parallèle
const [a, b] = await Promise.all([chargerStagiaire(1), chargerStagiaire(2)]);
console.log('Promise.all :', a.id, b.id);
node async.mjs
1. Demande envoyée
2. Suite du programme
3. Reçu : Amira
4. Terminé
async/await : Amira (DEV1)
async/await, erreur : Stagiaire -5 introuvable
Promise.all : 1 2
awaitest utilisé ici directement au niveau du fichier : c'est possible dans un module (.mjs) depuis ES2022. Ailleurs,awaitdoit être placé dans une fonctionasync.- Dans Angular : le client HTTP renvoie des Observables (bibliothèque RxJS) plutôt que des promesses. Le principe est le même : demander une donnée, continuer, puis traiter la réponse quand elle arrive. Ils seront étudiés dans le chapitre Communiquer via le client HTTP.
ECMAScript moderne dans le code Angular
- Voici un composant Angular annoté : chaque numéro correspond à une notion de cette leçon.

-
Compatibilité : du code moderne au navigateur
- Dans un projet Angular, le compilateur transforme le TypeScript en JavaScript selon la version indiquée par l'option
targetdu fichiertsconfig.json(ES2022dans les projets récents). - Cette transformation convertit la syntaxe (les mots-clés et opérateurs). En revanche, les nouvelles fonctions de la bibliothèque standard (
Object.groupBy(),Set.prototype.union()…) doivent exister dans le navigateur lui-même. Avant de les utiliser dans une application destinée au public, vérifiez leur prise en charge sur caniuse.com ou sur MDN.
- Dans un projet Angular, le compilateur transforme le TypeScript en JavaScript selon la version indiquée par l'option

-
Activité 5 : moderniser un programme ES5
- Le programme ci-dessous, écrit en ES5, calcule les bulletins d'un groupe de stagiaires. Le copier dans
05-es5.js, l'exécuter et noter le résultat.
- Le programme ci-dessous, écrit en ES5, calcule les bulletins d'un groupe de stagiaires. Le copier dans
var stagiaires = [
{ nom: 'Amira', groupe: 'DEV1', notes: [14, 16, 17] },
{ nom: 'Sami', groupe: 'DEV2', notes: [8, 11, 9] },
{ nom: 'Yasmine', groupe: 'DEV1', notes: [12, 10, 15] },
{ nom: 'Karim', groupe: 'DEV2', notes: [18, 16, 19] }
];
function calculerMoyenne(notes) {
var somme = 0;
for (var i = 0; i < notes.length; i++) {
somme = somme + notes[i];
}
return somme / notes.length;
}
function Bulletin(stagiaire) {
this.nom = stagiaire.nom;
this.groupe = stagiaire.groupe;
this.moyenne = calculerMoyenne(stagiaire.notes);
}
Bulletin.prototype.afficher = function () {
var mention = this.moyenne >= 10 ? 'Admis' : 'Ajourné';
return this.nom + ' (' + this.groupe + ') : ' + this.moyenne.toFixed(2) + ' / 20 - ' + mention;
};
var bulletins = [];
for (var j = 0; j < stagiaires.length; j++) {
bulletins.push(new Bulletin(stagiaires[j]));
}
var admis = [];
for (var k = 0; k < bulletins.length; k++) {
if (bulletins[k].moyenne >= 10) {
admis.push(bulletins[k].nom);
}
}
for (var m = 0; m < bulletins.length; m++) {
console.log(bulletins[m].afficher());
}
console.log('Admis : ' + admis.join(', '));
console.log('Nombre d\'admis : ' + admis.length + ' sur ' + bulletins.length);
- Dans
05-moderne.js, réécrire ce programme en JavaScript moderne, sans aucune bouclefornivar:constpartout ;calculerMoyenneen fonction fléchée avecreduce;Bulletinen classe, avec un constructeur qui déstructure le stagiaire ;afficher()avec un gabarit;- les bulletins avec
map, les admis avecfilterpuismap, l'affichage avecforEach.
- Vérifier que les deux programmes affichent exactement le même résultat :
Amira (DEV1) : 15.67 / 20 - Admis
Sami (DEV2) : 9.33 / 20 - Ajourné
Yasmine (DEV1) : 12.33 / 20 - Admis
Karim (DEV2) : 17.67 / 20 - Admis
Admis : Amira, Yasmine, Karim
Nombre d'admis : 3 sur 4

- Compter les lignes des deux versions et noter la différence en commentaire. Commit :
git commit -am "Activité 5 : programme modernisé"(pensez d'abord àgit addpour les nouveaux fichiers).
Activité 6 : découper en modules
- Créer un dossier
06-modules/et répartir le programme moderne de l'activité 5 dans trois fichiers :donnees.mjs: export nommé du tableaustagiaires;bulletin.mjs: export nommé decalculerMoyenneet export par défaut de la classeBulletin;index.mjs: importe le reste et affiche le résultat.
- Exécuter avec
node 06-modules/index.mjs: le résultat doit être identique à celui de l'activité 5. - Répondre en commentaire dans
index.mjs: que se passe-t-il si on oublie le mot-cléexportdevantcalculerMoyenne? Quel message affiche Node ?
Activité 7 : simuler un appel à une API
- Dans
07-async.mjs, écrire une fonctionchargerGroupe(code)qui renvoie une promesse tenue après 800 ms avec la liste des stagiaires du groupe ('DEV1'ou'DEV2'), ou rompue avec l'erreurGroupe XXX inconnupour tout autre code. - Écrire une fonction
async afficherGroupe(code)qui affiche « Chargement de DEV1… », attend la liste avecawait, puis affiche le nombre de stagiaires et leurs noms, ou le message d'erreur grâce àtry/catch. - Appeler
afficherGroupe('DEV1'), puisafficherGroupe('DEV9'). - Charger enfin les deux groupes en parallèle avec
Promise.all, mesurer la durée avecconsole.time('chargement')etconsole.timeEnd('chargement'), puis comparer avec deuxawaitsuccessifs. Expliquer la différence de durée en commentaire.
Activité 8 : défi ES2020 à ES2025
- Dans
08-defi.js, à partir des bulletins de l'activité 5, produire l'affichage ci-dessous en utilisant obligatoirement:toSorted(),at(-1),Object.groupBy(),Object.entries()avecfor…of,?.et??.
Classement : 1. Karim | 2. Amira | 3. Yasmine | 4. Sami
Major : Karim – Dernier : Sami
DEV1 : 2 stagiaires, moyenne 14.00
DEV2 : 2 stagiaires, moyenne 13.50
Sami : 9.33 – Ali : introuvable
- Vérifier en fin de programme que le tableau d'origine n'a pas été trié : son premier élément doit toujours être Amira. Pourquoi ce ne serait pas le cas avec
sort()? - Créer un fichier
README.mdqui liste les activités et les notions utilisées dans chacune, puis faire le dernier commit et le push.
Erreurs fréquentes
| Message ou symptôme | Cause | Solution |
|---|---|---|
TypeError: Assignment to constant variable. |
Réaffectation d'une variable déclarée avec const |
Utiliser let si la valeur doit vraiment changer |
ReferenceError: Cannot access 'x' before initialization |
Variable let ou const utilisée avant sa déclaration |
Déplacer la déclaration avant son utilisation |
Le gabarit affiche ${nom} tel quel |
Apostrophes ' ' au lieu d'accents graves ` ` |
Écrire la chaîne entre accents graves |
Une fonction fléchée renvoie undefined |
Accolades sans return, ou objet renvoyé sans parenthèses |
Ajouter return, ou écrire () => ({ … }) |
SyntaxError: Cannot use import statement outside a module |
import dans un script classique : balise <script> sans type="module" dans le navigateur, ou fichier .js avec une ancienne version de Node.js |
Ajouter type="module" à la balise <script>; avec Node, renommer en .mjs ou ajouter "type": "module" dans package.json |
SyntaxError: The requested module does not provide an export named 'x' |
Oubli de export, faute de frappe, ou export par défaut importé avec des accolades |
Vérifier le nom et le type d'export |
TypeError: Cannot read properties of undefined |
Accès à la propriété d'un objet absent | Utiliser ?. et prévoir une valeur avec ?? |
Le résultat d'une promesse s'affiche sous la forme Promise { <pending> } |
Oubli de await (ou de .then()) |
Ajouter await dans une fonction async |
TypeError: x.toSorted is not a function (ou groupBy, union…) |
Version de Node.js ou de navigateur trop ancienne | Mettre à jour Node.js (version LTS) ou vérifier la compatibilité du navigateur |
-
À retenir
- ECMAScript est la norme, JavaScript son implémentation ; TypeScript ajoute les types et les décorateurs à ECMAScript.
- ES6 (2015) a modernisé le langage ; depuis, une version sort chaque année.
constpar défaut,letsi la valeur change, jamaisvar.- Fonctions fléchées, gabarits, déstructuration, spread / rest et méthodes de tableaux rendent le code plus court et plus lisible.
- Les classes et les modules (
import/export) sont la base de toute l'architecture d'Angular. ?.et??protègent contre les données absentes ;async/awaitsimplifie le code asynchrone.
Lire du code Angular, c'est d'abord lire de l'ECMAScript moderne : chaque notion de cette leçon réapparaîtra dans vos composants et vos services.