IB CEGOS Défense · Formation à presentielle

Formation

Javascript programmation avancée

3 jours21 h10 chapitres
const subject = "JavaScript programmation avancée"

IB Cegos, avec Glodie Tshimini Septembre 2026

Ce support de cours est protégé par le droit d'auteur.

Toute reproduction, représentation, diffusion ou rediffusion, totale ou partielle, sur quelque support que ce soit, est strictement interdite sans l'accord express de l'auteur.

© Glodie Tshimini, 2026 - Tous droits réservés.

Programme

Ce que nous allons couvrir

01

Le mot-clé this

  • Comparaison avec les autres langage objet: une histoire de contexte d'exécution
  • Problème commun des fonctions asynchrones
  • Les closures
  • Les méthodes de la classe Function : call, apply et bind
02

Liste d'éléments : des alternatives aux boucles

  • Les méthodes de la classe Array
  • Algorithme de mapping (map)
  • Algorithmes de filtrage (filter)
  • Algorithmes d'agrégation ou de réduction (reduce)
03

Les architectures pré-ES2015

  • État du chargement des scripts dans le navigateur
  • Pollution du scope global
  • Absence d'isolation de code
  • Absence d'isolation de sémantique
  • Les IIFEs
  • Les script-loaders
04

ES2015

  • Contexte historique
  • Le TC39 et le système d'apport progressif
  • Let et const
  • Les objets littéraux avancés
  • Les string templates
  • Les fonctions fléchées
  • Les paramètres par défaut
  • Le paramètre du reste (rest)
  • La boucle for...of
  • La syntaxe de décomposition (spread)
  • Affectation par décomposition (destructuring)
  • La POO (nouvelles syntaxes des classes, héritage)
  • Les promesses
  • Async / Await
  • Les modules ES2015 (utilisation standard et module-bundlers)
Suite Programme

Ce que nous allons couvrir

05

Les packages et la transpilation

  • CommonJS : un système de module
  • Le gestionnaire de paquet npm
  • Le fichier package.json
  • Le problème de la rétro-compatibilité
  • La solution : Babel (AST, transformations)
  • Les plugins Babel
  • Les presets Babel
06

Typescript

  • Contexte historique
  • Définition
  • Configurations (CLI, tsconfig.json)
  • L'évolution parallèle de ECMAScript et de TypeScript
  • Le typage statique
  • Les types de bases
  • Les alias de type
  • L'inférence de type
  • Les interfaces
  • La POO (encapsulation, raccourcis de définition de propriété)
  • Typage des fonctions
  • La généricité
07

Web APIs et PWA

  • Qu'est-ce qu'une PWA ?
  • LocalStorage / SessionStorage
  • Cache
  • Fetch
  • Geolocation
  • Service workers
08

Tests

  • Les différents types de test
  • Test unitaire
  • Test d'intégration
  • Test fonctionnel (ou end-to-end)
  • Les tests runners
09

Introduction aux Librairies / Frameworks Front-End

  • Définition d'une librairie UI
  • Définition d'un framework front-end
  • SPA vs SSR
  • La philosophie des composants
  • Différences entre les principales technologies (React, Angular, Vue)
10

Bonus : Node.js et autres Web APIs

  • Introduction à la programmation serveur avec Node.js (modules http, path et fs)
  • Canvas / SVG
  • Page visibility API
Avant de commencer

Installations

Un éditeur de code de votre choix et Node JS
Chapitre 01

Le mot-clé this

4 notions
Avant de commencer

Quelles sont vos connaissances sur le mot-clé "this" ?

Chapitre 01 · Le mot-clé this
MotCleThis.comparaisonAutresLangageObjet()

Comparaison avec les autres langage objet : Une histoire de contexte d'exécution

Comprendre 1 / 4
💡 À retenir : regardez à gauche du point . au moment de l'appel !
POO (Javan C#, C++) JavaScript
Liaison this est lié à l'objet (instance de la classe) Liaison dynamique selon le contexte d'exécution
Défini À la compilation À l'exécution
Immutable (modifiable) Ne change jamais de valeur Peut changer
En conclusion Statique Dynamique

function whoami() {
  console.log(this);
}
// selon le contexte (Navigateur ou Node ou "use Strict") :
whoami();             // 1. Appel direct -> Window (Browser) ou globalThis (Node) ou undefined ("use strict")
myObject.whoami();    // 2. Appel via objet -> myObject
new whoami();         // 3. Constructeur -> Le nouvel objet créé
            

const user = {
  name: 'Alice',
  greet() {
    console.log(`Salut, je suis ${this.name}`);
  }
};
user.greet(); // (this = user)
            

function Car(model) {
  // 1. Un objet vide {} est créé
  // 2. 'this' pointe sur cet objet vide
  this.model = model; 
  // 3. L'objet est retourné automatiquement
}
const myCar = new Car('Tesla'); // this = myCar
console.log('myCar', myCar)
            
Doc. MDN sur l'opérateur this
Chapitre 01 · Le mot-clé this
MotCleThis.differentesNotations()

Comparaison avec les autres langage objet : une histoire de contexte d'exécution

Synthèse 1 / 4
Mode d'appel / Syntaxe Fonction traditionnelle Fonction fléchée
Notation function() {} () => {}
Appel simple (f()) window (navigateur) / global (Node) — ou undefined en strict mode this du contexte parent au moment de la création
Méthode d'objet (obj.f()) L'objet situé avant le point (obj) this du contexte parent (ignore obj)
Constructeur (new f()) La nouvelle instance créée Impossible (lève une erreur TypeError)
Gestionnaire d'événement (addEventListener) L'élément HTML ciblé (elem) this du contexte parent (souvent window)
Liaison explicite (call, apply, bind) Le premier argument transmis Ignore la liaison (conserve le this lexical)
Doc. opérateur this
Chapitre 01 · Le mot-clé this
MotCleThis.problemeCommunFonctionAsynchrone()

Problème commun des fonctions asynchrones

Rappels 2 / 4

Implémenter l'asynchrone avec JavaScript

  • Les méthodes setTimeout(), setInterval(), setImmediate()
  • Les fonctions callbacks utilisées dans la programmation événementielle (ex: .addEventListener())
  • Les promesses à travers les objets Promise et XMLHttpRequest
  • la fonction fetch(), une implémentation simplifié de l'objet Promise
  • Les mots clés async / await
Chapitre 01 · Le mot-clé this
MotCleThis.problemeCommunFonctionAsynchrone()

Problème commun des fonctions asynchrones

Faire 2 / 4
  • Perte de contexte de this lors des callbacks (API Web, setTimeout, événements), l'exécution étant décalée dans le temps, "this" n'est plus rattaché à l'objet.
  • Solutions pour garder le contexte initiale :
    • Stocker this dans une variable const self = this;
    • Utiliser la fonction .bind(this)
    • Utiliser la notation flechée () => { this.count++; }

const user = {
  nom: "Alice",
  hello() {
    setTimeout(function() {
      console.log(this.nom); // undefined !
      // "this" pointe sur window/global car la fonction anonyme est appelée séparément.
    }, 1000);
  },
  helloArrowFn() {
    setTimeout(() => {
      console.log(this.nom); // "Alice", conserve le "this" de l'objet user.
    }, 1000);
  }
};
              

class Counter {
  constructor() { this.count = 0; }
  start() {
    // Perte de this : la fonction est exécutée plus tard par le runtime
    setTimeout(function() {
      this.count++; // ❌ TypeError ou NaN !
    }, 1000);
  }
}
              

const service = {
  data: [1, 2, 3],
  load() {
    fetch('/api/data')
      .then(function(reponse) {
        // PERTE DE CONTEXTE
        this.save(reponse); // ❌ TypeError: Cannot read properties of undefined
      });
  },
  save(data) { /* ... */ }
};
              

class Counter {
  value = 0;
  async increment() {
    await new Promise(r => setTimeout(r, 100));
    this.value++; // Risque de perte si l'appel de la fonction est détachée
  }
}

const c = new Counter();
const action = c.increment

action(); // ❌ TypeError: Cannot read properties of undefined (reading 'valeur')     
              

const counter = {
count: 0,
start() {
  // La fonction passée à setTimeout est appelée de façon DIRECTE !
  setTimeout(function() {
    this.count++; // ❌ TypeError: Cannot read properties of undefined (ou NaN)
    console.log(this.count);
  }, 1000);
  }
};
// Quand setTimeout exécute la fonction de callback 1 seconde plus tard,
// il l'exécute en invocation directe (fn()). Le lien avec counter est brisé.
counter.start();
              
Chapitre 01 · Le mot-clé this
MotCleThis.closures()

Les closures

Comprendre 3 / 4
  • Définitions
    • Lexical environment (portée lexicale) : accessibilité d'une variable dans une structure imbriqué
    • Durée de vie d'une variable : cycle de vie determiné par la façon et l'endroit où la variable est déclarée
    • Closure : une fonction qui accède et conserve le scope parent même après la fin d'exécution de ce dernier.
    • Une closure permet à la fois de protéger les variables du scope parent et d'étendre leur durée de vie au-delà du temps d'exécution. Ses variables ne sont pas directement accessibles depuis l'extérieur, elles sont donc privées
    • Cas d'usage
      • Encapsulation/variables privées : les IIFE (pattern IIFE) et le prefixe # devant le nom de la variable
      • Le pattern Factory Function : création des fonctions à partir d'une fonction
      • Mémoïsation : stockage du résultat en cache pour une réutilisation future sans refaire le calcul
  • Le piège à éviter, la closure partagée avec var dans une boucle

for (var i = 0; i < 3; i++) {
  setTimeout(() => console.log(i), 100);
}
              
Chapitre 01 · Le mot-clé this
MotCleThis.methodesCallApplyEtBind()

Les méthodes de classe Function : call, apply et bind

Comprendre 4 / 4
💡 À retenir : Les fonctions call(), apply() et bind() permettent de contrôler le contexte d'exécution et donc la valeur de this !
call() apply() bind()
Signature call(thisArg, arg1, arg2, ...) apply(thisArg, [argsArray]) bind(thisArg, arg1, arg2, ...)
Arguments L'objet (this) et liste d'arguments L'objet (this) et tableau d'arguments L'objet (this) et liste d'arguments
Exécution Immédiate Immédiate Differé (au prochain appel)
Vérouillage de this (hard binding) Non Non Oui

function introduceDev(lang1, lang2) {
  console.log(`Je suis ${this.name} et je code en ${lang1} et ${lang2}`);
}
const bob = { name: 'Bob' };

introduceDev.call(bob, 'JS', 'TS');     // Exécutée immédiatement
introduceDev.apply(bob, ['JS', 'TS']); // Exécutée immédiatement
const bound = introduceDev.bind(bob, 'JS', 'TS'); // nouvelle fonction exécutable plus tard
console.dir(bound) // function...
bound(); // Exécutée
              
Atelier

Atelier 1.1

Le mot-clé this
Correction atelier

Correction Atelier 1.1

Le mot-clé this
Chapitre 02

Liste d'éléments : des alternatives aux boucles

4 notions
Avant de commencer

Quelles sont vos connaissances sur les tableaux et les méthodes associées ?

Chapitre 02 · Liste d'éléments : des alternatives aux boucles
AlternativesBoucles.methodesClassesArray()

Les méthodes de la classe Array

Comprendre 1 / 4

Les tableaux en JavaScript possède des méthodes très riches pour effectuer des opérations de base et complexes en toute simplicité

Utilisation des fonctions de manière déclarative ou impérative

Déclaratif Impératif
Définition Le quoi sans le comment, déclarer ce que l'on veut obtenir Le comment
Utilisation Les prototypes (Array.prototype) Les boucles (for, while, do while) avec index, condition, incrémentation
Caractéristiques Réutilisable, code plus lisible Traitement spécifique, code plus difficile à lire
Immutabilité (modification) Ne mute pas le tableau d'origine, renvoie un nouveau tableau calculé que l'on peut stocker dans un nouveau tableau Mute le tableau d'origine

Liste non exhautive de toutes les fonctions déclaratives

Source image Make Computer Science Great Again Source image Shreyas Hupare
Chapitre 02 · Liste d'éléments : des alternatives aux boucles
ListeElements.algorithmesMapping()

Algorithmes de mapping (map)

Comprendre 2 / 4
💡 À retenir : la taille du tableau final est stricte identique à l'initial !

Transformer chaque élément d'un tableau pour produire un nouveau tableau de même taille

map() passe 3 argument à la fonction callback

  1. Valeur de l'élément actuel
  2. index, position de l'élément dans le tableau
  3. le tableau d'origine

// Pour comprendre le fonctionnement, créons notre propre map()
Array.prototype.myMap = function(callbackFn) {
  const result = [];
  for (let i = 0; i < this.length; i++) {
    result.push(callbackFn(this[i], i, this));
  }
  return result;
};
          

Les pièges à éviter

  • parseInt() dans un map()
  • Modifier la valeur d'origine

// Erreur 
['1', '2', '3'].map(parseInt); // [1, NaN, NaN]
// parseInt prend (valeur, base numérique comprise entre 2 et 36 = radix) 
// parseInt reçoit ('1', 0), ('2', 1), ('3', 2). 
// radix 0 n'existe pas
    JS l'évalue dynamiquement ici à la base 10 (décimal)
    '1' en base 10 donne 1
// radix 1 n'existe pas => NaN
// radix 2 = base binaire (0 ou 1), 3 n'existe pas en binaire => NaN

// La correction :
['1', '2', '3'].map(num => parseInt(num, 10));
          

const users = [{ name: 'Alice' }, { name: 'Bob' }];
const copy = users.map(u => {
  u.role = 'admin'; // Modifie directement l'objet d'origine !
  return u;
});
// JS copie la référence de l'objet users (pas l'objet lui-même)
// Solution
const fix = users.map(u => {
  return {...u, role: 'admin'};
});
          
Chapitre 02 · Liste d'éléments : des alternatives aux boucles
Architecture.alternativesBoucles()

Algorithmes de filtrage (filter)

Comprendre 3 / 4
  • Extraire des éléments selon un prédicat (une fonction qui renvoie un booléen true ou false).
  • Le contenu est conservé par référence (pas de copie profonde des objets)
  • La règle d'or : La taille du tableau résultant est $\le$ à celle du tableau d'origine.
  • Le chainage (Chaining) est possible mais coûteux en performance, filter().map() parcourt 2 fois le tableau d'origine
  • Pour une meilleure performance sur un tableau volumineux (>= 10^6 éléments), lorsque l'on souhaite transformer et filtrer, il faut utiliser la fonction reduce()

const users = [
  { name: 'Alice', active: true, role: 'admin' },
  { name: 'Bob', active: false, role: 'user' },
  { name: 'Clovis', active: true, role: 'user' }
];

// Uniquement les noms des utilisateurs actifs
const activeUserNames = users
  .filter(user => user.active)
  .map(user => user.name);
              
Chapitre 02 · Liste d'éléments : des alternatives aux boucles
Architecture.algorithmeAgregationOuReduction()

Algorithme d'agrégation ou de rédution (reduce)

Comprendre 4 / 4
💡 À retenir : toujours préciser la valeur initiale !
  • Agréger un tableau = transformer un tableau en une seule valeur
  • Le piège de l'omission de la valeur initiale: Sans valeur initiale, le premier élément devient l'accumulateur et la boucle commence à l'index 1. Sur un tableau vide sans valeur initiale, JS lève une TypeError critique.

array.reduce((accumulator, currentValue, index, array) => {
  return newAccumulator;
}, initValue);
            

Cas d'usage 1 : Calcul d'agrégat (somme, moyenne, max)


const cart = [{ price: 39.99 }, { price: 12.95 }, { price: 19.99 }];
const total = cart.reduce((acc, article) => acc + article.price, 0);
              

Cas d'usage 2 : Restructuration de données (GroupBy par propriété)


const team = [
  { name: 'Alice', dept: 'Tech' },
  { name: 'Bob', dept: 'HR' },
  { name: 'Chantal', dept: 'Tech' }
];

const byDept = team.reduce((acc, emp) => {
const key = emp.dept;
if (!acc[key]) acc[key] = [];
  acc[key].push(emp.name);
  return acc;
}, {}); // Résultat : { Tech: ['Alice', 'Chantal'], HR: ['Bob'] }
          
fruits comparison between map(), filter(), reduce()
Source image Aritra Mondial
Exercice

Atelier 2.1

Liste d'éléments : des alternatives aux boucles
Correction exercice

Correction Atelier 2.1

Liste d'éléments : des alternatives aux boucles
Chapitre 03

Architectures pré-ES2015

6 notions
Avant de commencer

Quelles sont vos connaissances de la syntaxe avant pré-ES2015 (ES6) ?

Chapitre 03 · Les architectures pré-ES2015
Architecture.chargementScriptsNavigateur()

État du chargement des scripts dans le navigateur

Comprendre 1 / 6
Objectif : Rappeler le comportement par défaut de la balise <script> et ses limites techniques. L'exécution bloquante : À l'époque, placer des balises <script> dans le <head> bloquait le parsing HTML (rendu de la page interrompu le temps de télécharger et d'exécuter le fichier). La gestion manuelle de l'ordre d'évaluation :

              
              
              
              
              
              
Conséquence : Un graphe de dépendances implicite, géré à la main dans le fichier HTML. Si un fichier change d'ordre, tout l'applicatif casse silencieusement ou lève des erreurs Uncaught ReferenceError.

Un script ou une fonction closure contenant toute la logique du JavaScript

Architecture module en séparant la logique en plusieurs fichiers et combiné aux transpilers comme babel, Webpack pour réintégrer tout le code dans un seul fichier

Chapitre 03 · Les architectures pré-ES2015
Architecture.pollutionScopeGlobal()

La pollution du scope global

Comprendre 2 / 6

La majorité des variables déclarés avait le Function scope ou le Global Scope

Les librairies JS utilisées beaucoup la variable $, donc plusieurs librairies à cause du scope global pouvait rentré en collision à cause du scope global

Chapitre 03 · Les architectures pré-ES2015
Architecture.isolationCode()

Absence d'isolation de code

Comprendre 3 / 6
  • La logique d'un seul fichier contenant toute la logique de l'application
  • 1 fichier = plusieurs fonctions = plusieurs responsabilités
  • La maintenance difficile
  • avec un code très dense
Chapitre 03 · Les architectures pré-ES2015
Architecture.AbsenceIsolationSemantique()

Absence d'isolation de sémantique

Comprendre 4 / 6
Objectif : Illustrer le manque d'isolation syntaxique et sémantique de l'époque.
  • Pollution du scope global : Tout est injecté dans l'objet window et déclarée au niveau supérieur (top-level)
    • variables
    • fonctions
  • Absence d'isolation du code : Collision de noms identiques des variables (Name Collisions).
  • Absence d'isolation sémantique : Impossible de déclarer des éléments « privés ».
    • Tout le code source est accessible et modifiable depuis n'importe quel autre script ou la console du navigateur.

// Code d'Alice (alice.js)
var currentUser = { name: 'Alice' };
// Code de Bob (bob.js chargé après alice.js)
var currentUser = 'Bob'; // Écrase la déclaration d'Alice !
Chapitre 03 · Les architectures pré-ES2015
Architecture.IIFEs()

Les IIFEs

Comprendre 5 / 6
💡 À retenir : IIFE, fonction qui isole le code et s'auto-exécute !
  • IIFFE Immediately Invoked Function Expression, ou expression de fonction immédiatement invoquée
  • Mécanisme d'encapsulation qui s'appuie sur la portée de fonction (Function Scope)
  • Le principe est d'utiliser une fonction anonyme exécutée immédiatement pour isoler de variables grâce aux closures.

(function(global) {
    // Variable privée isolée du reste du monde
    var privateCounter = 0;
    function log() {
      console.log('Compteur :', privateCounter);
    }
    // Exposition explicite sur l'objet global (API publique)
    global.myModule = {
      increment: function() {
        privateCounter++;
        log();
      }
    };
  })(window);
            
Chapitre 03 · Les architectures pré-ES2015
ArchitecturescriptLoaders()

Les script-loaders

Comprendre 6 / 6
  • Problème : Les IIFEs isolent le code, mais ne gèrent pas le chargement dynamique ni l'ordre de téléchargement des fichiers.
  • Solution : Script loader, pour charger à la volée les dépendances (autres fichiers) dans l'ordre souhaitée
  • Script loader, ancêtre des bundlers (webpack, vite, etc.)
  • L'émergence des normes et des chargeurs ont permis de democratiser cette manière modulaire et dynamique de gérer les dépendances d'un projet.
  • Les normes
    • RequireJS (le plus populaire et celui qui s'est imposé jusqu'à l'arrivée d'ECMAScript)
    • AMD (Asynchronous Module Definition)
    • LABjs / Script46 : Injection dynamique de balises <script> via le DOM pour télécharger en parallèle et exécuter dans l'ordre. Le passage à CommonJS (Node.js) : Mentionner brièvement l'arrivée de Node.js (2009) avec module.exports et require(), qui a posé les bases de ce qu'allaient devenir les modules ES2015 (ESM).
    • Etc.

// Utilisation de require() pour charger à la volée les dépendances
define(['jquery', 'mathUtils'], function($, mathUtils) {
  return {
    init: function() { /* ... */ }
  };
});
            
Exercice

Atelier 3.1

Les architectures pré-ES2015
Correction exercice

Correction Atelier 3.1

Les architectures pré-ES2015
Chapitre 04

ES2015

15 notions
Avant de commencer

Quelles sont vos connaissances à partir de ES2015 (ES6) ?

Chapitre 04 · ES2015
ES2015.contexteHistorique()

Contexte historique

Comprendre 1 / 15

ECMAScript : comité de standardisation de JavaScript crée en

Une standardisation du langage qui s'est faite difficilement et avec un peu de retard par rapport au calendrier initialement fixé

  • La version ES2015(ES6) a eu 6 ans de retard
  • La stratégie initiale de tout déployé a été remplacé par des releases annuelle (ES2016, ES2017, etc.).
evolution of JS Article sur l'évolution de JS ample.com
Chapitre 04 · ES2015
ES2015.tc39SystemeApportProgressif()

Le TC39 et le système d'apport progressif

2 / 15

Le TC39 (Technical Committee 39) : Le comité chargé de faire évoluer ECMAScript.

Politique fixé en 5 étapes

  1. Stage 0 (Strawman) : Idée brute.
  2. Stage 1 (Proposal) : Cas d'usage et API préliminaire.
  3. Stage 2 (Draft) : Spécification précise du comportement.
  4. Stage 3 (Candidate) : Solution quasi finale, implémentée par les navigateurs/moteurs JS.
  5. Stage 4 (Finished) : Inclusion officielle dans la prochaine version annuelle.
Chapitre 04 · ES2015
ES2015.LetEtConst()

Let et Const

Comprendre 3 / 15
💡 À retenir : Abandonner la portée fonction (var) au profit de la portée de bloc (let et const) !

La portée (scope) définit l'accessibilité d'une variable en dehors du bloc où elle a été déclarée. Il y a 3 scopes :

  • Global scope : le bloc de plus haut niveau
  • Function scope : le bloc qui définit une fonction
  • Block scope : blocs de condition, boucles, etc.
var let const
Portée Fonction Bloc Bloc
Fonctionnement Hoisting (remonte en haut de la fonction en ignorant les blocs (if, for)) Restreint au bloc {} le plus proche Identique à let
Variable Accessible en dehors du bloc dans laquelle elle a été déclarée Accessible uniquement dans le bloc ou ellea été défini (n'existe pas en dehors) Identique à let
Immutabilité valeur Référence et valeur Référence, pas de la valeur.
Global scope Oui Non Non
Function Scope Oui Oui Oui
Bloc Scope Non Oui Oui
Réaffection Oui Oui Non
Redéclaration Oui Non Non

const user = { name: 'Alice' };
user.name = 'Bob'; // VALIDE ! La référence n'a pas changé.
user = {};        // TypeError: Assignment to constant variable.
            

//@see https://dasha.ai/blog/javascript-scope-and-scope-chain
// Global variable
const userName = "Peter";
// Outer function
function calcAge(birthyear) {
  const currentYear = 2021;
  const age = currentYear - birthyear;
   // inner block
  if (age <= 60) {
    var working = true;
    const message = `Peter is still employed!`;
    console.log(message);
  }
  // inner function
  function yearsToRetire() {
    const retirement = 60 - age;
    console.log(`${userName} will be retired in ${retirement} years!`);
  }
  yearsToRetire();
}
calcAge(1975);            
        
Scopes
Doc. sur let et les scopes Doc. sur var et les scopes Source image dasha
Chapitre 04 · ES2015
ES2015.objetLitterauxAvances()

Objets littéraux avancés

Comprendre 4 / 15
  • Propriétés raccourcies (Property shorthand)
    
    function makeUser(firstname, lastname, birth) {
      return { firstname : firstname, lastname: lastname, birth: birth }
    }
    // Avec Property shorthand
    function makeUser(firstname, lastname, birth) {
      return { firstname, lastname, birth }
    }
                    
  • Méthodes raccourcies
    
    // Avant
    { hello: function() {} }.
    // Après
    { hello() {} }
                    
  • Clés calculées (Computed property names)
    
    { [key]: value }.
                    
Chapitre 04 · ES2015
ES2015.StringTemplates()

Les string templates

Comprendre 5 / 15

String Templates (Gabarits de texte) :

  • Interpolation de variables ${expr} sans concaténation +.
  • Prise en charge native du multi-ligne.

const firstname = 'Glodie';
const lastname = 'Tshimini';
// Avant
console.info('Bonjour,\n c\'est ' + firstname + ' ' + lastname )
// Après
console.info(`Bonjour, 
c'est ${firstname} ${lastname}`
)
            
Chapitre 04 · ES2015
ES2015.fonctionsFlechees()

Les fonctions fléchées

Comprendre 6 / 15
💡 À retenir : Les arrow functions n'ont pas de this propre !

Fonctions fléchées (Arrow Functions) :

  • Écriture plus compact
  • Retour implicite des fonctions monophrases (sur une ligne)
    
    const hello = (name) => `Bonjour ${name}`
                    
  • Pas de contexte this propre : capture le contexte du englobant (parent)
    
    const counter = {
      count: 0,
      start() {
        // Recupère le 'this' de start() -> 'counter'
        setTimeout(() => {
          this.count++; // ✅
          console.log(this.count); // 1
        }, 1000);
      }
    };
                    
Chapitre 04 · ES2015
ES2015.parametresParDefaut()

Les paramètres par défaut

Comprendre 7 / 15

// Avant
function hello(firstname, lastname || '') {}
// Après
const hello = (firstname, lastname = '') {}
            
Paramètres par défaut : Évite les garde-fous historiques du type options = options || {}.
Chapitre 04 · ES2015
ES2015.parametresDuReste()

Paramètres du reste

Comprendre 8 / 15

Paramètre Rest (...args) : Remplace l'objet arguments en regroupant le reste des arguments reçus dans un tableau.


// Avant
function sumBefore(nb1, nb2, nb3) {
  var args = Array.from(arguments) // [nb1, nb2, nb3]
  console.log(
    arguments[0], // valeur de nb1
    arguments[1], // valeur de nb2
    arguments[2] // valeur de nb3
  )
}
// Après
function sumAfter(...args) {
  console.log(args)
}
sumAfter(1,2,3,4,5,6,7) // [1,2,3,4,5,6,7]
            
Doc. MDN arguments Doc. MDN paramètre Rest
Chapitre 04 · ES2015
ES2015.boucleForOf()

La boucle for...of

Comprendre 9 / 15

La boucle for...of parcourt les valeurs de tout objet itérable (Array, String, Map, Set, arguments).

Quant à la boucle for...in parcourt les clés (propriétés énumérables) d'un objet.


let nbs = [1, 2, 3];
const alice = { firstname: 'Alice', age: 32, city: 'London' };

for (let val of nbs) {
  console.log(nbs); // 1 2 3
}

for (const property in alice) {
console.log(`${property}: ${alice[property]}`);
// firstname: Alice age: 32 city: London
}
            
Doc. MDN boucle for...of Doc. MDN boucle for...in
Chapitre 04 · ES2015
ES2015.syntaxeDecomposition()

La syntaxe de décomposition (spread)

Comprendre 10 / 15
  • Extraire et combiner les données de façon déclarative.
  • Affectation par décomposition (Destructuring) sur les objets et les tableaux
    
      // Objet
      const user = { name : 'Alice', age : 21 };
      const { name, age: age } = user;
      console.log(name, age);
      // Tableau
      const numbers = [1, 2];
      const [first, second] = numbers;
      // avec permutation sans variable temporaire
      const [permutFirst, permutSecond] = [second, first];
      console.log(first, second, permutFirst, permutSecond)
                      
Chapitre 04 · ES2015
ES2015.affectionDecomposition()

Affectation par décomposition (destructuring)

Comprendre 11 / 15
  • Extraire et combiner les données de façon déclarative.
  • Syntaxe de décomposition (Spread Operator)
    
    const numbers = [1,9,5,45,16];
    const original = { media: 'video', type: 'mp4', at: new Date() };
    const alice = { firstname: 'Alice', age : 40 }
    const address = { 
      street: 'Etienne Marcel',
      num : 155,
      city : 'Paris',
      postal: 75001 
    }
    
    // Éclatement
    const maxNb = Math.max(...numbers); // Avant Math.max(1,9,5,45,16);
    console.log('max', maxNb);
    // Copie surpefielle (Shallow Copy)
    const clone = { ...original, updated: true };
    console.log('original', original);
    console.log('clone', clone);
    // Fusion
    const fullFusion = {...alice, ...address };
    const partialFusion = { ...alice, address };
    console.log('full', fullFusion);
    console.log('partial', partialFusion);
                      
Chapitre 04 · ES2015
ES2015.poo()

La POO (nouvelles syntaxes des classes, héritage)

Comprendre 12 / 15
💡 À retenir : JavaScript n'est pas un langage objet, tout est objet ! 💡 À retenir : la syntaxe de classe est possible grâce au sucre syntaxique basé sur les prototypes!
  • Syntaxe de base des classes plus proche et fidèle aux autres langages objets Java/C++
    • Constructeur de l'objet avec la méthode constructor()
    • Méthodes de classe et méthodes statiques (static)
    • getters/setters (get/set)
    • Héritage prototypal : extends sur la classe et appel obligatoire au constructeur parent via super()
    • Propriétés privées

class JavaScript {
  // Propriété (prop.) privée (encapsulation)
  #creator = 'Brendan Eich';
  // Propriété statique (partagée au niveau de la classe)
  static createdAt = 1995;

  constructor(version, isDynamicallyTyped = true) {
    this.version = version; // Propriété publique
    this.isDynamicallyTyped = isDynamicallyTyped;
  }

  info() {  // Méthode d'instance
    return `JavaScript (${this.version}) - Créé en ${JavaScript.createdAt} par ${this.#creator}.`;
  }

  static compareVersion(v1, v2) {
    return `Comparaison entre la version ${v1} et la version ${v2}.`;
  }

  get creator() {
    return this.#creator;
  }
}

class TypeScript extends JavaScript {
  static createdAtTypeScript = 2012;   // Propriété statique propre à la classe fille

  constructor(version, versionCompiler) {
    super(version, false); // Appel du constructeur parent classe JavaScript
    this.versionCompiler = versionCompiler; // Propriété spécifique à TypeScript
  }

  info() { // Surcharge (override) de la méthode d'instance
    const basicInfo = super.info();
    return `${basicInfo}\n TypeScript y ajoute le typage statique (compilateur v${this.versionCompiler}).`;
  }

  compiler() {   // Méthode propre à la classe fille
    return `Transpilation du code TypeScript (v${this.versionCompiler}) vers JavaScript (${this.version})...`;
  }
}

// 1. Instanciation de la classe mère
const es6 = new JavaScript('ES6');
console.log('•', es6.info()); 

// 2. Accès à la méthode et propriété statiques
console.log('• Created : ', JavaScript.createdAt);
console.log('•', JavaScript.compareVersion('ES5', 'ES6'));

// 3. Instanciation de la classe fille
const ts5 = new TypeScript('ES2022', '5.0');
console.log('•', ts5.info()); 
console.log('• TS typage dynamique : ', ts5.isDynamicallyTyped);
console.log('•', ts5.compiler());
              
Chapitre 04 · ES2015
ES2015.promesses()

Les promesses

Comprendre 12 / 15
💡 À retenir : Preférez Promise.all() à l'enchainement sequentiel de async/await !
  • Meilleur visibilité et gestion de l'asynchrone par rapport aux callbacks et notamment à l'imbrication des callbacks (Callback Hell)
  • Les 3 états :
    1. pending (en attente)
    2. fulfilled (résolue)
    3. rejected (rompue).
  • Chaînage via 3 méthodes :
    1. .then() : exécutée en cas de succès
    2. .catch() : exécutée en cas d'erreur
    3. .finally() : exécutée dans tous les cas de figure
  • Combinaison de plusieurs promesses (agrégation parallèle) à travers 3 méthodes
    1. Promise.all()
      • Résolue si toutes les promesses réuississent, toute la promesse est rejectée dès le premier échec
      • Idéal lorsqu'on veut tout ou rien
    2. Promise.allSettled()
      • Attend que toutes les promesses soient terminés peu import le résultat (succès ou échec)
      • Idéal pour charger des ressources indépendantes
    3. Promise.race()
      • Renvoie le résultat du premier terminé (succès ou échec)
      • Idéal pour des ressources similaires externes avec des temps de chargement (timeout) différents
Promises Chaining Promise states Doc. MDN Promise Source image @Pawan Kumar
Chapitre 04 · ES2015
ES2015.promesses()

Les promesses

Faire 12 / 15

function fetchData(resource, timeOut, isSuccess = true) {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      if (isSuccess) {
        resolve(`[OK] Données reçues de ${resource} en ${timeOut}ms`);
      } else {
        reject(new Error(`[Error] : Échec de connexion à ${resource}`));
      }
    }, timeOut);
  });
}
// Promesse simple
fetchData('API Utilisateurs', 1000)
  .then((result) => console.log(result))
  .catch((error) => console.error(error.message));

const p1 = fetchData('API 1', 1000, true);
const p2 = fetchData('API 2', 2000, true);
const p3 = fetchData('API 3', 500, true);
const pError = fetchData('API 4 Défaillante', 800, false);

// Promise.all()
Promise.all([p1, p2, p3]) // s'arrête à la première erreur
  .then((results) => {
    console.log('Promise.all() Succès', results);
  })
  .catch((error) => console.error('Promise.all() a échoué :', error.message));
  
Promise.all([p1, pError, p3])
  .catch((error) => {
    console.log('Promise.all() Échec');
    console.log(error.message); // Stoppe immédiatement dès l'échec de pError
  });

// Promise.allSettled()
Promise.allSettled([p1, pError, p3])
  .then((results) => {
    results.forEach((res, index) => {
      if (res.status === 'fulfilled') {
        console.log(`Promise.allSettled() : ${index + 1} réussie :`, res.value);
      } else {
        console.log(`Promise.allSettled() : ${index + 1} échouée :`, res.reason.message);
      }
    });
  });

// C. Promise.race()
Promise.race([p1, p2, p3])
  .then((winner) => {
    console.log('Promise.race() le plus rapide est :', winner);
  })
  .catch((error) => console.error('Promise.race() le plus rapide a échoué :', error.message));
              
Chapitre 04 · ES2015
ES2015.asyncAwait()

Async / Await

Comprendre 13 / 15
  • async / await en utilisant du sucre syntaxique sur les promesses, rend le code
    • Plus lisible avec une illusion d'une exécution séquentielle.
    • Plus propre avec une gestion des erreurs via les blocs try...catch.
  • Les mots-clés async et await fonctionnent généralement de pair.
  • A éviter :
    • Melanger les async/await avec .then()
    • D'exécuter async/await en série (plus long que Promise.all())

function fetchData(resource, timeOut, isSuccess = true) {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      if (isSuccess) {
        resolve(`[OK] Données reçues de ${resource} en ${timeOut}ms`);
      } else {
        reject(new Error(`[Error] : Échec de connexion à ${resource}`));
      }
    }, timeOut);
  });
}

// async/await avec Promise.all()
async function all() {
  console.log('Async/Await avec Promise.all');
  // Démarrant toutes en parallèle et immédiatement
  const p1 = fetchData('API 1', 1000, true);
  const p2 = fetchData('API 2', 2000, true);
  const p3 = fetchData('API 3', 500, true);

  try {
    // await met en pause la fonction jusqu'à résolution de toutes les promesses
    const results = await Promise.all([p1, p2, p3]);
    console.log('Succès :', results);
  } catch (error) {
    console.error('Échec :', error.message);
  }
}

async function allWithError() {
  const p1 = fetchData('API 1', 1000, true);
  const pError = fetchData('API 2 Défaillante', 800, false);

  try {
    await Promise.all([p1, pError]);
  } catch (error) {
    console.log('Promise.all() échoue avec erreur attrapée via try/catch', error.message);
  }
}

// async/await avec Promise.race
async function race() {
  const p1 = fetchData('API 1', 1000, true);
  const p2 = fetchData('API 2', 2000, true);
  const p3 = fetchData('API 3 (plus rapide)', 500, true);

  try {
    const winner = await Promise.race([p1, p2, p3]);
    console.log('Le plus rapide est :', winner);
  } catch (error) {
    console.error('La plus rapide a rejeté une erreur :', error.message);
  }
}

(async function() {
  await all();
  await allWithError();
  await race();
})();
              

function fetchData(resource, timeOut, isSuccess = true) {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      if (isSuccess) {
        resolve(`[OK] Données reçues de ${resource} en ${timeOut}ms`);
      } else {
        reject(new Error(`[Error] : Échec de connexion à ${resource}`));
      }
    }, timeOut);
  });
}
(async function(){
  // OK bonne pratique
  console.time('all')
  const p1 = fetchData('API 1', 1000);
  const p2 = fetchData('API 2', 1000);
  const results = await Promise.all([p1, p2]); // Durée totale ~1000ms
  console.log('Promise.all', results)
  console.timeEnd('all')
  // KO mauvaise pratique
  console.time('asyncAwait')
  const r1 = await fetchData('API 1', 1000); // Attend 1000ms
  const r2 = await fetchData('API 2', 1000); // Attend 1000ms (Total ~2000ms)
  console.log('asyncs', r1, r2)
  console.timeEnd('asyncAwait')
})()
              
Chapitre 04 · ES2015
ES2015.modules()

Les modules ES2015 (utilisation standard et module-bundlers)

Comprendre 15 / 15

Un module est un fichier JavaScript répondant à un besoin spécifique et qui peut être partagé ou réutilisé dans d’autres scripts JS. Plusieurs standards d’utilisation existent en JavaScript : CommonJS et ESM sont les deux les plus utilisés.

Module explanation
  • Le standard ECMAScript à utiliser pour les modules
    • Module avec le Standard ECMAScript est supporté nativement par les navigateurs
    • Syntaxe (import / export)
    • Export nommés
    • Export défault
    • Balise type="module"
    • Mode strict
    • Chargement differé (attribut defer sur la balise script) après le chargement complet du DOM
  • L'utilisation des modules avec les bundlers(Vite, Webpack, Rollup, etc.) apporte des fonctionnalités supplémentaires tels que
    • Optimisation du code
    • Retrocompatibilité avec les vieux navigateurs (polyfills)
    • Regrouper le CSS et tous modules JS dans une seule fichier principal chargé par le HTML (bundling)
    • Suppression du code et des dépendances mortes (Tree-Shaking)
    • Transpiler le code écrit en une autre version de JS (transpilation)

// Module src/utils/fech-data.js
const fetchData = () => {};
const interneFn = () => {};
export {
  api: fetchData
};

// Module src/utils/format.js
export const formatDate = () => {};
export const formatMessage = () => {};
const formatFinance = () => {};

// Module src/classes/product.js
export default class Product {};

// Point d'entrée de l'application src/main.js
mode 'strict';
import { api } from '../utils/fetch-data.js';
import Article from '../classes/product.js';
import { formatDate, formatMessage } from '../utils/format.js';

// Fichier /index.html
<body>
  <script src="src/main.js" type="module"></script> 
</body>
              
Source image @miracerdin Medium
Exercice

Atelier 4.1

ES2015
Correction exercice

Correction Atelier 4.1

ES2015
Chapitre 05

Les packages et la transpilation

7 notions
Avant de commencer

Quelles sont vos connaissances sur les packages et la transpilation ?

Chapitre 05 · Les packages et la transpilation
Package.commonJS()

CommonJS : un système de module

Comprendre 1 / 7
  • CommonJS est le standard historique de Node.js
  • N'est pas supporté nativement par les navigateurs, nécessite l'utilisation d'un transpiler tels que Webpack, Babel pour fonctionner côté Front
  • Le chargement des fichiers se fait depuis le module fs de système de fichiers (file system)
  • Le chargement des modules est synchrone, dynamique
  • Import dynamique, il est possible d’appeler la fonction require() depuis n’importe quel endroit dans son code (pas spécialement en haut comme ci-dessous)
  • Syntaxe
    • Exportation : module.exports = { ... } ou exports.myFunc = ...
    • Importation : const fs = require('fs');
    • Extension des fichiers : .cjs
    • Type de module dans le package.json : "type": "commonjs"
CommonJS versus ESM Source image Lenguajejs
Chapitre 05 · Les packages et la transpilation
Package.npm()

Le gestionnaire de paquet npm

Comprendre 2 / 7
  • NPM (Node Package Manager) est un gestionnaire de dépendances de Node
  • NPM est aussi un registre permettant d'installer les dépendances d'un projet et gérer le dossier /node_modules
  • Le dossier /node_modules contient toutes les dépendances d'un projet (les modules installés)
  • L'orchestration des dépendances s'effectue en ligne de commande (CLI) et en utilisant les fichiers package.json et package-lock.json
  • Environ 4.4M de packages disponibles sur le site officiel https://www.npmjs.com/
  • Il existe d'autres gestionnaire de paquet pour JS
    • Yarn : 10 fois plus rapide, plus fiables dans les versions, il partage de dépendances entre plusieurs projets et a une meilleure gestion de l’espace mais ça passe par les serveurs de Facebook
    • PNPM : Plus performant et plus optimisé pour la gestion de l’espace (dépendances avec des liens symboliques vers un cache centralisé), il n'est pas compatible avec tous les paquets
    • Bun : Un seul outil qui remplace npm/yarn/Node et Webpack, c'est le plus rapide, il est compatible avec les paquets npm. Pas suffisamment mature mais concurrent très redoutable pour devenur leader Back-end JS
Registry officiel NPM Yarn PNPM Bun
Chapitre 05 · Les packages et la transpilation
Package.packageJson()

Le fichier package.json

Comprendre 3 / 7

Le fichier package.json est une pièce maitresse d'un projet JS, contenant :

  • Les informations sur votre projet (nom, description, auteur, etc.) et la configuration (version du projet, version npm, node, etc.)
  • Les scripts disponibles en CLI à exécuter (par exemple le lancement de l'application, les tests, la compilation, etc.)
  • Les versions des dépendances principales au format MAJOR.MINOR.PATCH, par exemple "typescript": "^5.6.0"
    • ^ autorise les mises à jour PATCH et Minor, la version précédente de TypeScript peut être téléchargée en 5.*.* par exemple 5.6.8 dans le projet
    • ~ autorise uniquement les mises à jour PATCH donc 5.6.* par exemple 5.6.9
    • Sans symbole, il s'agit d'une version fixe, plus sécurisée
  • Les dépendances en production et en développement
    • Les dépendances en production identifiées par la clé dependencies, ce dernier contient les modules nécessaires au fonctionnement de l’application en production par exemple le module pour la base de données MySQL, SQLite, MongoDB, etc.
    • Les dépendances en développement par la clé devdependencies, modules utilisés uniquement lors du développement par exemple pour tester votre application ou compiler le JS.
      Des modules qui ne sont pas indespensables pour le production et à ne surtout pas déployer (alourdir le projet pour rien)

Le fichier package-lock.json

  • stocke les dépendances sécondaires (modules utilisés par vos modules) de vos dépendances principales, indispensable pour garantir les mêmes versions du projet entre 2 développeurs
  • Ne jamais modifier ce fichier, npm le gère à partir de vos commandes CLI

// Fichier package.json
{
  "name": "shopping",
  "private": true,
  "author": "John Doe <john@doe.com>",
  "license": "ISC",
  "version": "1.4.0",
  "type": "module",
  "scripts": {
    "dev": "vite",
    "build": "vite build",
    "preview": "vite preview",
    "start": "npx serve -s dist -p 80"
  },
  "devDependencies": {
    "@tailwindcss/vite": "^4.3.2",
    "@tailwindplus/elements": "^1.0.22",
    "@types/leaflet": "^1.9.21",
    "tailwindcss": "^4.3.2",
    "typescript": "~6.0.3",
    "vite": "^8.1.3"
  },
  "dependencies": {
    "leaflet": "^1.9.4",
    "nanoid": "^6.0.0",
    "simplycountdown.js": "^3.0.1"
  }
}
// Extrait fichier package-lock.json
{
  "name": "shopping",
  "version": "1.4.0",
  "lockfileVersion": 3,
  "requires": true,
  "packages": {
    "": {
      "name": "shopping",
      "version": "1.4.0",
      "dependencies": {
        "leaflet": "^1.9.4",
        "nanoid": "^6.0.0",
        "simplycountdown.js": "^3.0.1"
      },
      "devDependencies": {
        "@tailwindcss/vite": "^4.3.2",
        "@tailwindplus/elements": "^1.0.22",
        "@types/leaflet": "^1.9.21",
        "tailwindcss": "^4.3.2",
        "typescript": "~6.0.3",
        "vite": "^8.1.3"
      }
    },
    "node_modules/@emnapi/core": {
      "version": "1.11.1",
      "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.11.1.tgz",
      "integrity": "sha512-RSvbQmHzdKzNsLYa/wHrbc3KN4sYLKAdPZxqiM2HATqv/SBk2/ENSHpvXGaLOMcsAyz0poEGqkmmKYG3OWiJEQ==",
      "dev": true,
      "license": "MIT",
      "optional": true,
      "dependencies": {
        "@emnapi/wasi-threads": "1.2.2",
        "tslib": "^2.4.0"
      }
    },
    ...
  }
}
            
Chapitre 05 · Les packages et la transpilation
Package.packageJson()

Le fichier package.json

Faire 2 / 7

Les commandes NPM

    1. Initialiser un nouveau projet : npm init
    2. Installer toutes les dépendances du projet à partir du fichier package.json en autorisant des versions différentes selon les symboles utilisées : npm install
      • Notation courte : npm i
      • Installer avec exactement les mêmes dépendances définis dans package-lock.json : npm ci
    3. Installer un paquet de manière globale (sur toute la machine indépendamment d'un projet) : npm i -g webpack
    4. Installer les modules pour tous les environnements : npm install react mongodb
    5. Installer les modules uniquement pour le développement : npm install -D typescript vitest supertest cypress
    6. Désinstaller un module : npm uninstall supertest
    7. Mettre à jour un module : npm update cypress
    8. Publier un module pour la communauté : npm login et npm publish --access public
      Pour ce dernier point, il faut respecter les conditions de création d'un module et les recommandations de publication de npmjs
Chapitre 05 · Les packages et la transpilation
Package.retroCompatibilite()

Le problème de la rétro-compatibilité

Comprendre 4 / 7
  • Concept fondamental en programmation qui consiste à faire évoluer un langage tout en s'assurant que le code écrit avec les nouvelles ou anciennes versions continu de fonctionner avec les environnements (navigateur ou Node) récents et anciens.
    • Un code écrit avec la dernière version ES2025 fonctionnera sur un vieux navigateur ou une vielle version de Node
    • Un code écrit avec une syntaxe pré-ES2015 fonctionnera sur la dernière version de votre navigateur.
  • Attention à rester vigilant sur les fonctionnalités dépréciées (délais suffisamment longues pour faire la migration), dans ce cas de précis, l'application ne fonctionnera plus
  • Il y aura toujours un décalage entre la vitesse d'évolution du langage et la mise à jour des environnements d'exécution.
  • La rétro-compatibilité répose sur 2 concepts clés :
    1. Transpilation : Traduire une syntaxe récente non supportée vers une syntaxe ancienne équivalente, par exemple, tranformer une arrow function () => {} en function() {}
    2. Polyfill (API) : Rajouter au runtime une méthode ou un objet manquant dans le prototype, par exemple, apporter Array.prototype.includes
Chapitre 05 · Les packages et la transpilation
Package.babel()

La solution : Babel (AST, transformations)

Comprendre 5 / 7
  • Babel est un transpileur (transpiler) : Compilateur permettant la retrocompatibilité du code JS pour transformer du code JS moderne en pré-ES2015 (ES5)
  • Son fonctionnement en 3 étapes :
    1. Parsing (analyse lexicale et syntaxique) : Le code JS brut est converti Arbre de Syntaxe Abstrait (Abstract Syntax Tree (AST)).
    2. Transformation : Des plugins parcourent cet AST et modifient/remplacent les nœuds syntaxiques modernes par des nœuds ES5.
    3. Generation : L'AST modifié est reconverti en chaîne de caractères de code JavaScript exécutable.
    
    code Source (ES2015+) => [ Parsing ] => AST => [ Transformation ] => AST modifié => [ Generation ] => Code Cible (ES5)
                    

Les transpilers les plus populaires

  • Webpack : le plus connu et abouti, cependant sa configuration peut être longue et pénible
  • Vite : rapide à mettre en place, écosystème Vue JS
  • Esbuild : sans configuration, commandes via le terminal et le plus performant (rapide)
  • Parcel : sans configuration également, des fonctionnalités supplémentaires via l'ajout de des plugins
  • Tsc : compiler le TypeScript en JS
  • Babel : le compilateur le plus connu pour assurer la rétrocompatibilité
Article comparaison transpilers Webpack Vite Parcel Esbuild TypeScript Babel
Chapitre 05 · Les packages et la transpilation
Package.babel()

Les plugins Babel

Comprendre 6 / 7
  • Les plugins Babel permettent d'étendre les fonctionnalités du module
  • Chaque module effectue une transformation spécifique
  • Les plugins peuvent être configurés depuis les fichiers babel.config.json ou .babelrc
  • Quelques modules Babel facilement installable avec npm i --save-dev [nom plugin]
    • @babel/plugin-transform-arrow-functionstransformer
    • @babel/plugin-transform-typescript
    • @babel/plugin-transform-for-of
    • @babel/plugin-transform-destructuring
Liste des plugins Babel
Chapitre 05 · Les packages et la transpilation
Package.presetsBabel()

Les presets Babel

Comprendre 7 / 7
  • Preset : ensemble de plugins pré-packagés pour répondre à un besoin global et éviter de faire une installation un à un
  • A partir d'un environnement cible, le preset est capable d'appliquer les transformations nécessaires
  • Quelques presets :
    • @babel/preset-env pour toute la syntaxe ES2015+
    • @babel/preset-typescript pour TypeScript
    • @babel/preset-react pour React

// babel.config.json
{
  "presets": ["babel-preset-myPreset", "@babel/preset-env"]
}
// babel-preset-myPreset/index.js
module.exports = function(api, options) {
  return {
    plugins: [
      "@babel/plugin-transform-typescript"
    ]
  };
};
           
Babel Presets
Exercice

Atelier 5.1

Les packages et la transpilation
Correction exercice

Correction Atelier 5.1

Les packages et la transpilation
Chapitre 06

TypeScript

12 notions
Avant de commencer

Quelles sont vos connaissances sur TypeScript ?

Chapitre 06 · TypeScript
TypeScripthistorique()

Contexte historique

Comprendre 1 / 12
  • Créé par Microsoft (Anders Hejlsberg, concepteur de C#) en 2012
  • Pour permette à Microsoft de migrer ses logiciels notamment la suite Office sur le web. JavaScript n'était pas suffisamment robuste pour permettre cette migration
  • La stratégie a été de créer un superset (sur-ensemble syntaxique) qui vient s'ajouter à JavaScript pour combler les lacunes du langage JS dont notamment les erreurs à l'exécution
Chapitre 06 · TypeScript
TypeScriptdefinition()

Définition

Comprendre 2 / 12
  • TypeScript est un sur ensemble typé de JavaScript (Typed Superset) qui se compile (ou transpiles) en JavaScript native.
  • Tout code JS valide est du code TS valide
  • Les navigateurs ne comprennent pas le TypeScript
  • Les versions récentes de Node sont directement compatible avec TypeScript
  • Fonctionnalités phares : les types et les classes.
Chapitre 06 · TypeScript
TypeScriptconfiguration()

Configurations (CLI, tsconfig.json)

Comprendre 3 / 12
💡 À retenir : npx tsc --init pour générer la configuration de TypeScript !
  1. Installer TypeScript : npm i -D typescript
  2. Configurer TypeScript depuis le fichier tsconfig.json à créer ou placer à la racine du projet
  3. Créer ou transformer les fichiers js en TypeScript en commançant par modifier l'extension [m|c].js en .ts
  4. Ajouter la nouvelle syntaxe que nous allons voir dans vos fichiers .ts
  5. Compiler avec l'outil CLI tsc mise à disposition par TypeScript pour transformer du TypeScript en JS
  6. Compiler le TypeScript en JS : npx tsc ou vérifier la syntaxe sans créer les fichiers .js npx tsc --noEmit
  • Zoom sur le fichier de configuration tsconfig.json
    • target : Version cible du code JS finale généré (ex: ES2024, ESNext)
    • module : Système de gestion des modules (ex: NodeNext, ESNext, commonjs)
    • strict: Vérifications strictes ou non du typage
    • rootDir: Dossier contenant vos sources (ex: /src)
    • outDir: Dossier de sortie des sources compilés et à servir pour la production (ex: /dist)

// tsconfig.json
{
  "compilerOptions": {
    "module": "CommonJS",
    "moduleResolution": "Node",
    "lib": ["ES2020"],
    "target": "ES2019",
    "strict": false,
    "skipLibCheck": true,
    "forceConsistentCasingInFileNames": true,
    "incremental": true,
    "esModuleInterop": true,
    "resolveJsonModule": true,
    "noEmitOnError": true,
    "noImplicitThis": true,
    "outDir": "dist",
    "rootDir": "."
  },
  // Include root, all ts files, js files
  "include": ["./", "./**/*.ts", "./**/*.js"],
  "exclude": ["node_modules/", "build/", "dist/", ".cache/", ".tmp/"]
}
            
Doc. complète options configuration TypeScript
Chapitre 06 · TypeScript
TypeScriptevolution()

L'évolution parallèle de ECMAScript et de TypeScript

Comprendre 4 / 12
  • TypeScript est aligné avec l'évolution de JS parce qu'il suit strictement les spécifications du TC39
  • Dès qu'une fonctionnalité syntaxique atteint le Stage 3/4 dans ECMAScript, elle est intégrée dans TS
Chapitre 06 · TypeScript
TypeScripttypageStatique()

Le typage statique

Comprendre 5 / 12
JavaScript TypeScript
Typage Dynamique Statique
Quand ? à l'exécution à la compilation
Chapitre 06 · TypeScript
TypeScripttypageBases()

Les types de bases

Comprendre 6 / 12
Types primitifs Exemple
String
let color: string = "orange";
Boolean
let isDone: boolean = false;
Number
let age: number = 56;
Les autres types Exemple
Array

let numbers: number[] = [1, 2, 3];
// ou
let numbers: Array<number> = [1, 2, 3];
                  
any

// Joker, any peut-être n'importe quel autre type (à éviter car il désactive la vérification du type)
let user: any = { firstname: 'Alice' };
user.hello(); // pas d'erreur malgré le fait que hello() n'est pas défini
user(); // pas d'erreur
user.age = 36; // pas d'erreur
user = "Alice"; // pas d'erreur
                  
unknown

// Mieux que any car il vérifiera le type qui devra être spécifié à l'utilisation
let champion2027 : unknown;
undefinied
let champion2027 : undefined = undefined
null
let notExist : null = document.querySelector('#notExist')
void

// Pas de valeur de retour de la fonction 
let deleteUser() : void {}
                    
Chapitre 06 · TypeScript
TypeScriptaliasType()

Les alias de type

Comprendre 7 / 12
  • Définir ses propres types
  • Les différentes manière de nommer ces types
    1. Types basiques :
      type User = { firstname: string, age: number, newsletter: boolean }
    2. Types unions :
      type Status = 'pending' | 'success' | 'error';
    3. Types intersections :
      type Admin = User & { permissions: string[] };
Chapitre 06 · TypeScript
TypeScriptinference()

L'inférence de type

Comprendre 8 / 12
💡 À retenir : Laisser TypeScript inférer sur les types simples ! 💡 À retenir : Annoter (typer) les fonctions et les structures complexes !
  • L'inférence de type (Type Inference) désigne la capacité de TypeScript à déduire automatiquement le type à partir de la valeur de la variable sans annotation explicite
    
    const age = 19 ; // déduction type nombre
    const alice = {
      firstname: 'Alice',
      age,
      isAdmin : false
    } // déduction également
                    
Chapitre 06 · TypeScript
TypeScriptinterfaces()

Les interfaces

Comprendre 9 / 12
  • Une Interface est un contrat de classe ou une description d'une structure objet
  • Principalement utilisé pour étendre les objets
  • 2 Interfaces portant le même nom fusionnent (Declaration Merging)
  • Quelles différences avec le typage traditionnelle ?
Interface Type
Usage POO, APIs, modules tierces Pour un usage classique, primitifs, unions, interceptions, types utilitaires
Exemple d'utilisation Typage de l'objet document du DOM par extension de l'objet
Chapitre 06 · TypeScript
TypeScript.POO()

La POO (encapsulation, raccourcis de définition de propriété)

Comprendre 10 / 12
  • Nous avons vu que la POO avec JS était possible partiellement par l'intermédiaire du sucre Syntaxe (derrière utilisation du prototypage)
  • TypeScript va un peu plus loin en ajoutant des nouvelles fonctionnalités
    1. Modificateurs d'accès : public (par défaut), private, protected
    2. Le modificateur readonly : La valeur d'une propriété ne peut plus être modifié après l'initialisation
    3. Raccourci de la déclaration du constructeur (absence de corps)
    4. Implémentation d'interfaces
    5. Classes abstraites (abstract) : classe non instanciable qui sert de base d'héritage pour les autres classes
    6. Etc.

// src/entities/user.ts
class User {
  constructor(
    public firstname: string,
    private age: number,
    public readonly id: string
  ) {}
}

// src/interfaces/storage.ts
export default Interface Storage {}
// src/utilities/my-mongodb.ts
import Storage from '../interfaces/storage'
class MongoDB implements Storage { ... }

// src/views/base.ts
export default Abstract class Base {
  abstract render();
  abstract fetchData();
}
// src/views/user-view.ts
import BaseView from './base'
Class UserView extends BaseView {
  render(){...}
  fetchData() {...}
}

              
Chapitre 06 · TypeScript
TypeScripttypageFonctions()

Typage des fonctions

11 / 12
  • Typer les paramètres d'entrée (valeurs simples ou callbacks) et retour (valeur retourné ou absence de valeur void par la fonction)
  • Les spécificités du typage d'une fonction
    • Paramètres par optionnels identifiables par ? après le nom du paramètre
    • Valeurs par défaut
    • Surchage des fonctions (Function Overloads) en déclarant plusieurs signatures pour la même fonction

/**
* tax valeur par défaut 0.2
@return un nombre
*/
function vat(price: number, tax: number = 0.2): number {
  return price * (1 + tax);
}
// fullname est optionnel
function register (email: string, password: string, fullname?: string) {}

// typage des callbacks
type CustomPromise = (
  url : string,
  onSucces: (data: string) => void,
  onError: (error: { message: string, status: number = 500 }) => void
  onEnd? : () => void
) : void {};

// Surchage
function makeDate(timestamp: number): Date;
function makeDate(m: number, d: number, y: number): Date;
function makeDate(mOrTimestamp: number, d?: number, y?: number): Date {
  if (d !== undefined && y !== undefined) {
    return new Date(y, mOrTimestamp, d);
  } else {
    return new Date(mOrTimestamp);
  }
}
const fromTimestamp = makeDate(Date.now());
const fromNumbers = makeDate(9, 7, 2026);
              
Chapitre 06 · TypeScript
TypeScriptgenericite()

La généricité

12 / 12
  • La généricté permet d'avoir un typage flexible
  • Elle permet la réutilisation du code et donc facilite la maintenance
  • Comment cela fonctionne ?
    • Les types génériques sont des alias, on utilise généralement la lettre T
    • S'il y a plusieurs types génériques à la suite, on utilise T, U, V, etc.
    • L'inférance effectue les traductions de types à partir des valeurs

// La fonction conserve le type de l'élément passé en paramètre
function firstElement<T>(arr: T[]): T | undefined {}
const num = firstElement([1, 2, 3]); // Inférance T est un number
const str = firstElement(['a', 'b']); // Inférance T est un string

// extension du type T qui doit obligatoirement posséder une propriété length de type number
function logLength<T extends { length: number }>(arg: T): T {
  console.log(arg.length);
  return arg;
}
Interface ApiResponse<T> {...}
Class Entity<T> {...}
              
Exercice

Atelier 6.1

TypeScript
Correction exercice

Correction Atelier 6.1

TypeScript
Chapitre 07

Web APIs et PWA

6 notions
Avant de commencer

Quelles sont vos connaissances sur Web APIs et le Progressive Web Application ?

Chapitre 07 · Web APIs et PWA
()

Qu'est-ce qu'une PWA ?

Comprendre 1 / 6
  • PWA (Progressive Web App) est une application web qui offre une expérience utilisateur quasi-identique à celle d'une application mobile native
    • Une PWA utilise les matériels (gps, bluetooth, caméra, micro, gyroscope, capteur luminosité, etc. ) et des fonctionnalités (notifications, mode hors-ligne, etc.) disponibles sur un smartphone
    • L'expérience enrichie par le PWA est possible grâce à l'exploitation des web APIs
    • S'installe et s'ajoute sur l'écran d'accueil
    • Ne nécessite pas d'installation depuis un Store d'applications (AppStore ou PlayStore)
    • Tout le fonctionnement répose sur les services workers
Chapitre 07 · Web APIs et PWA
WebAPI.storage()

LocalStorage / SessionStorage

Comprendre 2 / 6
  • L'API Web Storage (window.localStorage & window.sessionStorage) permettent de réaliser du stockage côté client (sur le navigateur).
  • Le stockage repose sur un couple clé-valeur n'acceptant que des strings (chaînes de caractère)
  • Le stockage est synchrone
  • Pour stocker les objets, il faut les sérialiser(transformer un objet en string) à l'aide de la fonction JSON.stringify(object)
  • Pour récupérer un objet depuis le storage (stockage), il faut déserialiser(transformer un string en objet) avec la fonction JSON.parse(string)
  • Sécurité faible à cause des attaques XSS (Cross-Site Scripting), il convient de ne pas stocker des données sensibles dans le Storage
LocalStorage SessionStorage
Durée de persitance Prérenne Durée de la session, les données s'effacent à la fermeture de l'onglet
Taille ~ 10Mo à 50Mo selon les navigateurs ~ 5Mo
Disponibilité des clés-valeurs Partout, tous les onglets du même site auront accès Uniquement l'onglet ou fénêtre en cours, 2 onglets = 2 sessions différentes
Usages Préférences utilisateur, données persistantes stables, les données provenant des APIs ou de votre serveur Données temporaires, informations saisies dans un formulaire
A ne pas stocker Données sensibles, les tokens, infos CB, etc. Données sensibles, les tokens, infos CB, etc.
Chapitre 07 · Web APIs et PWA
WebAPI.cache()

Cache

Comprendre 3 / 6
💡 À retenir : l'API Cache est indépendant du cache du Navigateur !
  • Le cache est uns système de stockage clé/valeur stockant des ressources réseau (requêtes et réponses HTTP) de manière asynchrone
  • Le cache du navigateur met en cache les informations à partir des en-têtes HTTP de la réponse du serveur
    Par exemple, la plus part des serveurs sont configurés pour demander au navigateur de mettre les images en cache pendant 30 jours
  • 3 stratégies pour le cache
    1. Cache First, falling back to Network : recherche d'abord dans le cache, si l'information est absente, recherche sur le réseau. idéal pour le contenu statique
    2. Network First, failing back to Cache : réseau -> échoue -> cache, idéal pour les données mis à jour fréquemment et gestion du hors-ligne (perte de connexion Internet)
    3. Stale-While-Revalidate : renvoie le courant courant et met à jour le nouveau cache via un appel réseau
  • Comment l'Interface Cache fonctionne ?

// Création d'un espace de cache
const myCache = await caches.open('assets-v1.0.0');

// Mise en cache
await myCache.addAll(['/main.css', '/index.js', '/favicon.ico', '/logo.svg']);

// Récupérer une ressource depuis le cache
const styleCss = await cache.match('/main.css');

              
Doc. Interface Cache
Chapitre 07 · Web APIs et PWA
WebAPI.fetch()

Fetch

Comprendre 4 / 6
  • fetch() est une notation simplifée d'une promesse(Promise) avec du sucre syntaxique
  • Les specificités de fetch() par rapport à une Promesse classique
    1. fetch ne rejette la promesse qu'en cas d'erreur réseau (pas de connexion).
      Il convient d'avoir une étape intermédiaire pour vérifier que le serveur répond favorable
    2. Les codes HTTP 40x ou 50x ne sont pas considérés comme un échec pour l'API fetch()
    3. Gère les en-têtes HTTP grâce à un objet Headers que l'on peut passer dans les options (2ème paramètre de la fonction)

(async function() {
  try {
    const res = await fetch('https://api.github.com/users/defunkt');
    // étape intermédiaire pour vérifier la réponse du serveur
    if (!res.ok) throw new Error(`HTTP Error: ${res.status}`);
    const data = await res.json();
    console.log('userGithubInfo', data);
  } catch (error) {
    console.error('[KO] :', error);
  }
})()

              

// POST en utilisant les options (2ème paramètre)
fetch('https://jsonplaceholder.typicode.com/posts', {
  method: 'POST', // valeurs possibles GET (par défaut), POST, PUT et DELETE
  // Données attendues par le serveur toujours en chaîne de caractère (sérialisation de l'objet)
  body: JSON.stringify({
    title: 'Cours sur JavaScript avancé',
    body: 'Incroyable 😉',
    userId: 1,
  }),
  headers: {
    'Content-type': 'application/json; charset=UTF-8',
  },
})
  .then((response) => response.json())
  .then((json) => console.log('réponse du serveur', json))
  .catch(error => console.log('[KO]', error));

              
Chapitre 07 · Web APIs et PWA
WebAPI.geolocation()

Geolocation

Comprendre 5 / 6
  • l'API geolocation permet d'obtenir les coordonnées géographiques (latitude et longitude) d'un utilisateur
  • Ses caractéristiques
    • Fonctionne uniquement avec le protocole HTTPS
    • Asynchrone
    • Temps réel
    • Demande d'une autorisation explicite (navigateur affiche un onglet pour accepter ou refuser la géolocalisation)
    • Signatures des fonctions de l'API
      1. navigator.geolocation.getCurrentPosition(successCallback, errorCallback?, options?)
      2. navigator.geolocation.watchPosition(successCallback, errorCallback?, options?)
      3. navigator.geolocation.clearWatch(id)
Doc. getCurrentPosition() Doc. watchPoistion() Doc. clearWatch() Doc. options de géolocalisation
Chapitre 07 · Web APIs et PWA
WebAPI.geolocation()

Geolocation

Faire 5 / 6

(function(){
  if (!navigator.geolocation) {
    console.error("Géolocalisation n'est pas supporté par le navgigateur");
    return;
  }
  let id;
  const options = {
    enableHighAccuracy: false,
    timeout: 5000,
    maximumAge: 0
  };
  // Obtenir la position actuelle (latitude, longitude, précision).
  navigator.geolocation.getCurrentPosition(
    (position) => console.log('Lat', position.coords.latitude, 'Lng', position.coords.longitude),
    (error) => console.error('[KO]', error),
    options
  );

  // Suivre les déplacements en temps-réel
  id = navigator.geolocation.watchPosition(
    (position) => {
      const { latitude, longitude } = position.coords
      if(latitude === 48.8893946 && longitude ===  2.2428192) {
        console.log('Vous êtes arrivé !');
        navigator.geolocation.clearWatch(id); // Arrêt du suivi              
      }
    },
    (error) => {
      switch(error.code) {
        case error.PERMISSION_DENIED:
          console.error('Accès refusée');
          break;
        case error.POSITION_UNAVAILABLE:
          console.error('Localisation indisponible');
          break;
        case error.TIMEOUT:
          console.error("Temps écoulé");
          break;
        case error.UNKNOWN_ERROR:
          console.error("Erreur inconnu");
          break;
      }
    },
    options
  );
})
              
Chapitre 07 · Web APIs et PWA
WebAPI.workers()

Service workers

Comprendre 6 / 6
  • Un service worker est un fichier JavaScript exécuté dans un thread séparé (Web Worker), sans accès direct au DOM.
  • C'est un programme s'exécutant en arrière plan
  • Il joue le rôle de middleware pouvant intercepter toutes les requêtes HTTP sortantes du programme principal
  • Il communique avec le thread principal (programme principal) grâce aux événements
  • Cycle de vie associées aux événements
    1. Enregistrement : le programme principale souscrit (déclenche) le service Worker
    2. Installation (associé à l'évenement install) : premier événement envoyé au service worker
    3. Activation (associé à l'événement activate) : une fois que l'installation ou une nouvelle version a été réalisé avec succès
  • Les autres événements applicatifs (fonctionnels)
    1. fetch : reception d'un message depuis le thread principal ou interceptions des requêtes sortantes
    2. sync : diffère les actions pour les exécuter lorsque la connexion réseau sera retablie
    3. push : envoyer des notifications même lorsque le navigateur n'est pas actif (lancé)
  • Usages :
    • Support hors-ligne : resiliance de l'application en mode dégradé (perte ou connexion instable)
    • Performance : réponse plus rapide depuis le cache
    • Notification push
    • Application plus réactif: le lancement des opérations lourdes ou critiques en arrière plan ne bloquent pas l'interface utilisateur
Doc. Service Worker
Chapitre 07 · Web APIs et PWA
WebAPI.workers()

Service workers

Faire 6 / 6
Exercice

Atelier 7.1

Web APIs et PWA
Correction exercice

Correction Atelier 7.1

Web APIs et PWA
Chapitre 08

Tests

5 notions
Avant de commencer

Quelles sont vos connaissances sur les tests automatisés ?

Chapitre 08 · Tests
Tests.differentsTypes()

Les différents types de test

Comprendre 1 / 5
  • Un test automatisé (par oppisition à un test manuel) est l'écriture d'un code supplémentaire permettant de vérifier qu'une brique, un scénario ou une fonctionnalité complète correspond au comportement ou résultat attendu
  • Pourquoi tester ?
    1. Documenter les comportements et les résultats attendus
    2. Rendre l'application plus robuste en détectant les problèmes avant la mise en production
    3. Faire évoluer et maintenir son application en toute confiance
    4. Faciliter le refactoring
    5. Améliorer la qualité du code avec une approche TDD (Test-Driven Development) qui consiste à tester avant de coder
    6. Réduire le coût de la maintenance en cas de bug (le temps passé à écrire un test est un investissement rentable pour le futur)
    7. Etc.
Chapitre 08 · Tests
Tests.differentsTypes()

Les différents types de test

Comprendre 1 / 5
Type Qu'est-ce qui est testé ? Caractéristiques Librairies
Unitaire tester les plus petites unités de code (ex: branche d'une condition) nombreux, rapides, peu coûteux (temps d'écriture) et très tables dans le temps Jest, Vitest, etc.
D'intégration tester au moins 2 unités de code qui collaborent ensemble pour donner un résultat (ex: une fonction) nombreux, plutôt rapides et relativement peu coûteux et stables Jest, Vitest, Supertest, etc.
Fonctionnelle tester une fonctionnalité bout à bout Peu nombreux, lents, coûteux et moins stables (fragile à la moindre modification de l'UI) Playwright, Cypress, etc.
Performance temps de charge, mémoire consommée, montée en charge, etc. Tester les performances de l'application à partir des ressources (cpus, mémoire) et des critères de qualité bien définis (temps de réponse,) Peu nombreux, rapide, peu coûteux et stables
Doublés Imulent (Simulent) le plus souvent des traitements lourds (une fonction complexe, une connexion à une base de données, l'appel d'une API, etc.) en fournissant directement le résultat attendu. Les tests doublés sont beaucoup utilisés dans le cadre de la réalisation des tests unitaires et d'intégration selon la complexité des fonctions à émuler le coût et le temps d'écriture peuvent augmenter, stables Jest, Vitest, Supertest, etc.
Sécurité Simuler des cyberattaques (instruisons et recherche de failles) Coûteux Un autre métier, Pentester
Etc.

Pyramide des tests de Mike Cohn

testing pyramide

Plus on monte dans la pyramide, plus le temps d'écriture, le coût, le temps d'exécution et le niveau de confiance sur la fonctionnalité ou l'application augmentent.

Source image @amaralisa Medium
Chapitre 08 · Tests
Tests.unitaire()

Test unitaire

Comprendre 2 / 5
  • Principe : isoler et tester la plus petite unité de code
  • Caractéristiques
    • Rapide d'écriture et d'exécution < 1 seconde
    • Périmètre : fonctions et classes métiers
    • Stable dans le temps, ne dépend pas de l'interface utilisateur (UI) et de la base de données (BDD)
    • S'abstraire de la complexité de certaines fonctions ou API en utilisant les tests doublés pour l'isolation du code.
      Vocabulaire des tests doublés
      • Stub : remplace un composant externe par une réponse prédéfinie
      • Spy : observe les appels faits à une fonction (combien de fois, avec quels arguments)
      • Mock : objet pré-programmé avec des attentes précises sur les interactions qu'il doit recevoir
  • Les librairies disponibles pour réaliser les tests unitaires
    • Test Runner (node:test) : librairie native et embarquée par Node
    • Jest : librairie de référence pour les tests unitaires avec JavaScript
    • Vitest : plus rapide et compatible Jest, développé par les créateurs des solutions et outils VueJS et Vite, support nativement le standard ECMAScript
    • Mocha
    • Etc.
Chapitre 08 · Tests
Tests.unitaire()

Test unitaire

Faire 2 / 5
  1. Installez une librairie dédié au tests unitaires : npm i -D vitest
  2. Ajoutez un script dans le fichier package.json
    
    // package.son
    {
      "scripts" : {
        "test" : "vitest"
      }
    }
                    
  3. Ajoutez la configuration de Vitest dans le fichier vitest.config.js pour qu'il détecte automatiquement les fichiers dediés aux Tests
    
    // vitest.config.js
    import { defineConfig } from 'vitest/config'
    export default defineConfig({
      test: {
        globals: true,
        testTimeout: 100,
        coverage: {
          reporter: ['html'],
          reportsDirectory: './tests/coverage'
        },
        environmentMatchGlobs: [
          [
            'tests/*/*.test.[c|m]js',
            'tests/*/*integration*.test.{js,mjs,cjs,ts}',
            'node',
          ]
        ],
        exclude: ['node_modules', 'tests/*']
      }
    })
    
                    
  4. Écrivez votre test en respectant le pattern AAA (Arrange, Act, Assert) et dans cet ordre d'écriture (Assert->Act->Arrange)
    • Arrange : préparation du contexte (charger les fonctions, les données nécessaires à l'exécution)
    • Act : appeler la fonction à tester
    • Assert : vérifier le comportement ou le résultat est bien celui attendu

// tests/cart/index.test.mjs
import  { describe, test, it, expect } from 'vitest';
import { computeTotal } from '../src/cart/index'
describe('Testing compute function', () => {
  test('It should be 80 € When price=100 and discount=0.2 (20%)', () => {
    // 1. ARRANGE
    const cart = [ { price: 100 } ];
    const discount = 0.2;
    // 2. ACT
    const result = computeTotal(cart, discount);
    // 3. ASSERT
    expect(result).toBe(80);
  });

  // it() alias de test()
  it('Should be 500€ without discount', () => {
    expect(computeTotal([{ price: 100}, { price: 400}], 0)).toBe(500);
  })
})
              
Chapitre 08 · Tests
Tests.integration()

Test d'intégration

Comprendre 3 / 5
  • Principe : vérifier que plusieurs briques de votre appplication fonctionnent correctement ensemble.
  • Caractéristiques
    • Connecter plusieurs briques de code ensemble et sans isolation.
    • Moins rapide que les tests unitaires, cependant, les doublures peuvent être utilisées pour reduire la complexité et le temps d'exécution
    • Périmètre: APIs externes, connexion à la base de données, les routes d'une application, module, le DOM
    • Les libraires
Chapitre 08 · Tests
Tests.integration()

Test d'intégration

Faire 3 / 5
  1. Installez les librairies vitest et supertest pour tester les routes d'une application : npm i -D vitest supertest
  2. Ajoutez un script dans le fichier package.json
    
    // package.son
    {
      "scripts" : {
        "test" : "vitest" // déjà présente (lance à la fois les unitaires et d'intégration)
      }
    }
                    
  3. Reprenez la configuration de vitest.config.js cf. l'étape 3 de la mise en place d'un test unitaire
  4. Écrivez votre test en respectant le pattern AAA

import { describe, expect, it } from "vitest";
import request from "supertest";
import app from "../src/app.mjs";
describe("Testing /teams routes", () => {
  describe("Testing GET /teams", () => {
    it("Should have JSON content", () => request(app).get("/teams").expect("Content-Type", /json/));
    it("Should have status 200", () => request(app).get("/teams").expect(200));
    it("Should have an array of teams", () => {
      return request(app)
        .get("/teams")
        .then((response) => {
          expect(Array.isArray(response.body)).toBe(true);
        });
    });
  });

  describe("Testing POST /teams", () => {
    it("Should have 201 status", () => {
      return request(app)
        .post("/teams")
        .send({ id: "10", name: "Lyon" })
        .set("Accept", "application/json")
        .expect(201);
    });
    
    it("Should have JSON content", () => {
      return request(app)
      .post("/teams")
      .send({ id: "10", name: "Lyon" })
      .set("Accept", "application/json")
      .expect('Content-Type', /json/);
    });

    it("Should have body response { message, success: true }", () => {
      return request(app)
      .post("/teams")
      .send({ id: "10", name: "Lyon" })
      .set("Accept", "application/json")
      .then(response => {
        expect(response.body).toEqual({ message: 'Team created', success: true})
      });
    });

    it("Should have status 500 (bad JSON sent)", () => {
      return request(app)
      .post("/teams")
      .send({})
      .set("Accept", "application/json")
      .expect(400)
      .then(response => {
        expect(response.body).toEqual({ 
          message: 'new team should have an id and a name', 
          success: false
        });
      })
    });
  });
});
              
Chapitre 08 · Tests
Tests.integration()

Test fonctionnel (ou end-to-end)

Comprendre 4 / 5
  • Principe : tester le parcours réel d'un utilisateur depuis l'interface utilisateur (UI) de bout en bout (end to end, abrégé E2E)
  • Caractéristiques
    • Exécuté dans un navigateur piloté par la librairie de test
    • Moins stable dans le temps dépend fortement de l'UI et des informations stockées en base de données
    • Périmètre : parcours utilisateur au complet avec les intéractions sur l'UI (utilisation souris, clavier), automatisation d'une recette (livraison)
  • Les livrairies
Chapitre 08 · Tests
Tests.integration()

Test fonctionnel (ou end-to-end)

Faire 4 / 5
  1. Installez une librairie dédiée : npm i -D cypress
  2. Ajoutez un script dans le fichier package.json
    
    // package.son
    {
      "scripts" : {
        "e2e" : "cypress open" // mode interactive en lançant et en suivant les tests en direct
        "e2e:headless" : "cypress run" // arrière-plan sans le lancement du navigateur
      }
    }
                    
  3. Lancez votre application disponible sur un port par exemple http://localhost:8080
  4. Configurez Cypress depuis cypress.config.js pour définir le point d'entrée (lien de votre application)
    
    // cypress.config.js
    import { defineConfig } from 'cypress';
    export default defineConfig({
      e2e: {
        baseUrl: 'http://localhost:8080',
        specPattern: 'cypress/e2e/*/*.cy.{js,mjs,jsx,ts,tsx}',
        supportFile: false
      },
    });
                    
  5. Ecrivez votre test E2E

// cypress/app/homepage.cy.js
describe("Testing homepage", () => {
  beforeEach(() => cy.visit('/'););
  it("Should have h1", () => cy.get("h1").should("exist"););
  it("Should have 2 links", () => cy.get("a").should("have.length.at.least", 2););
  it("Should go to /users", () => {
    cy.get("a[href=/users]").click();
    cy.get(".card").then((cards) => expect(cards.length).toBe(20););
  });
});
// cypress/app/login.js
describe("Testing Login page", () => {
  it("Should go to /login", () => {
    cy.visit("/login");
    cy.get('input[type=email]').type('john@doe.com', { delay: 100 });
    cy.get('input[type=password]').type('Admin123!', { delay: 100});
    cy.get('input[type=email]').should('have.value', 'john@doe.com');
    cy.get('input[type=password]').should('have.value', 'Admin123!');
    cy.get('input[type=submit]').click();
    cy.url().should('eq', 'http://localhost:8080/dashboard');
  });
});
              
Chapitre 08 · Tests
Tests.runners()

Tests runners

Rappels 5 / 5
  • Un test runner est un outil en ligne de commande (CLI) qui lance les fichiers de tests à partir d'un fichier de configuration qui lui permet de les reconnaitre
  • Le module s'accompagne des fonctions dédiées aux tests tels que before(), beforeEach(), after(), afterEach(), describe(), it(), test(), expect()
  • Rappels sur les runners vues précedemment
    • Vitest : moderne ultra-rapide basé sur Vite. Supporte nativement le standard ESM et TypeScript sans configuration
    • Cypress : pour les tests E2E
    • Node.js Native Test Runner (node:test) : runner intégré nativement dans Node.js pour tester sans dépendances extérieur à partir des versions Node >= 18
    • Etc.
Exercice

Atelier 8.1

Tests
Correction exercice

Correction Atelier 8.1

Tests
Chapitre 09

Introduction aux Librairies / Frameworks Front-End

5 notions
Avant de commencer

Quelles sont vos connaissances sur les Frameworks Front-End ?

Chapitre 09 · Introduction aux Librairies / Frameworks Front-End
Libraire.definitionUI()

Définition d'une librairie UI

Comprendre 1 / 5
  • Une librairie est un ensemble de fonctionnalités repondant à un besoin précis par exemple JQuery dont l"objectif était de simplifier l'écriture du code et son exécution sur différents navigateurs.
  • Le développeur utilise les outils mises à sa disposition comme il entend
  • Absence de cadre de travail ou ce dernier très léger et libre
  • Vous êtes le seul maître à bord
Chapitre 09 · Introduction aux Librairies / Frameworks Front-End
Librairie.framework()

Définition d'un framework front-end

2 / 5
  • A l'inverse d'une librairie, un framework est un cadre complet et strict
  • Le développeur écrit le code en fonction du cycle de vie (création, montage, mise à jour, etc.) et des conventions imposées
  • C'est le framework qui met le cap sur la direction à prendre dans le projet
Chapitre 09 · Introduction aux Librairies / Frameworks Front-End
Librairie.SPAVsSSR()

SPA vs SSR

Comprendre 3 / 5
SPA (Single Page Application) SSR (Server Side Rendering)
Principe Rendu effectué côté client (navigateur) Rendu effectué à la demande côté serveur par un langage de programmation Back-Ebd (Node, PHP, Ruby, Python, J2E, etc.)
Fonctionnement
  • Le serveur renvoie un seul et unique fichier HTML avec un body ayant un seul enfant par exemple <body><div id="app"></div>
  • Le client gère toute la logique et l'affichage de l'application
  • La construction du DOM est dynamique
Le JS basique qui sert uniquement à manipuler le DOM pour ajouter les intéractions
Avantages L'interface Utilisateur (UI) est très fluide et rapide, la navigation s'effectue sans rechargement de la page
  • Temps de chargement de la première page est très rapide
  • SEO meilleur
Inconvénients Le premier chargement est plus long, le référencement naturel SEO (scan du contenu de l'application par les robots des moteurs de recherche pour les reférencer dans les résultats de recherche) est pénalisé
Usage Les librairies et framework JS spécialisés dans l'affichage de l'UI tels que React, Vue Les meta-framework modernes (framework construit par-dessus d'un librairie ou framework) Next pour React, Nuxt pour Vue et Angular Uniservel
Chapitre 09 · Introduction aux Librairies / Frameworks Front-End
Librairie.composants()

Philosophie des composants

Comprendre 4 / 5
  • La logique derrière les composants est de découper l'interface en plusieurs briques autonomes et réutilisables
  • Ainsi une page HTML est composé de plusieurs composants indépendantes, mis les uns après les autres pour obtenir l'affichage final
  • Un composant Parent est un composant qui utilise d'autres composants considérés comme des composants enfants
  • Comment est constitué un composant ?
    1. La structure HTML/JSX (JavaScript XML) : code HTML ou JSX (HTML melangé avec du JS) responsable de l'affichage
    2. La logique : code JS responsable du comportement et des intéractions avec les éléments HTML affichés
    3. L'apparence (style) : code CSS
  • Comment les données sont échangées entre les composants ?
    1. Le flux de transmission des données est unidirectionnel du parent vers l'enfant et en lecture seule appelé props
    2. La communication de l'enfant au parent s'effectue à travers des événements et des callbacks exécutées par le parent
Chapitre 09 · Introduction aux Librairies / Frameworks Front-End
Librairie.benchmark()

Différences entres les principales technologies (React, Angular, Vue)

Comprendre 5 / 5
React Angular Vue
Création, gouvernance 2011 (2013 en Open Source) par Facebook (Meta) 2010 (réecriture en 2016) Google (Alphabet) 2014 par Evan You (ancien de Google) avec la communauté Open Source
Type Librairie Framework Intermédiaire entre librairie et framework
Langages JS/TS TS JS/TS
Syntaxe UI JSX HTML enrichi des directives HTML/JSX
Courbe (difficulté) d'apprentissage Modérée (moyenne) Raide (dure) Douce (facile)
Popularité sur GitHub (nombre d'étoiles) 249.1k ⭐​ 101k ⭐​ 54.3k ⭐​
Popularité selon le dernier sondage StateOfJS 2026 🥇 85% des répondants l'ont utilisé et l'évolution est croissante dans le 🥉 52%, croissance 🥈 48%, phase décroissante puis stabilisation​
Gestion du DOM Virtual DOM, une copie légère et partielle d'une partie du DOM réel permettant de faire des mises à jour très rapide des composants sans recharger tout le DOM dans son intégralité Incremental DOM / Signals, un DOM réel et des mécanismes pour recharger le composant dont les données ont été mises à jour à partir de Vue 3, Virtual DOM et Signals
Philosophie Composants Architecture d'entreprise Intuitive
Usage Petit à moyen projet de complexité faible à moyenne Moyen à grand projet de complexité moyenne à élevée Petit à complexité faible à moyenne
State Of JS 2025
Chapitre 09 · Introduction aux Librairies / Frameworks Front-End
Librairie.benchmark()

Différences entres les principales technologies (React, Angular, Vue)

Faire 5 / 5

import React, { useState, useEffect } from 'react';
export default function Counter() {
  const [count, setCount] = useState(0); // variable réactive

  useEffect(() => { // MAJ de l'élément titre document à chaque changement de valeur de count
    document.title = `Clics : ${count}`;
  }, [count]);

  return (
    <div style={{ textAlign: "center", marginTop: "1rem" }}>
      <p>Vous avez cliqué {count} fois</p>
      <button onClick={() => setCount(count + 1)}>Incrementer</button>
    </div>
  );
}
              

<script setup>
  import { ref } from 'vue'
  const counter = ref(0) // variable réactive
  function increment() {
    counter.value++
  }
</script>

<template>
  <div>
    <p>Vous avez cliqué {{ counter }} fois</p>
    <button @click="increment">Incrementer</button>
  </div>
</template>

<style scoped>
button {
  font-size: 1.5rem;
  cursor: pointer;
}
</style>
              

// counter.component.ts
import { Component, signal } from '@angular/core';

@Component({
  selector: 'app-counter',
  standalone: true,
  templateUrl: './counter.component.html',
  styleUrls: ['./counter.component.css']
})
export class CounterComponent {
  count = signal(0); // Déclaration du signal avec une valeur initiale de 0

  increment() {
    this.count.update(value => value + 1);
  }
}
// counter.component.html
<div class="counter-container">
  <h2>Compteur : {{ count() }}</h2>
  <div class="buttons">
    <button (click)="increment()">Incrementer</button>
  </div>
</div>
              
Exercice

Atelier 9.1

Introduction aux Librairies / Frameworks Front-End
Correction exercice

Correction Atelier 9.1

Introduction aux Librairies / Frameworks Front-End
Chapitre 10

Bonus : Node.js et autres Web APIs

3 notions
Avant de commencer

Quelles sont vos connaissances sur Node.js ?

Chapitre 10 · Bonus : Node.js et autres Web APIs
NodeEtAutresAPIs.introduction()

Introduction à la programmation serveur avec Node.js (modules http, path et fs)

Comprendre 1 / 3
  • Node est un environnement (technologie) d’exécution Javascript côté serveur crée en 2009 par Ryan Dahl
  • Composé de :
    • Moteur V8 (C++) de chrome : interprète et exécute le code JavaScript
    • NPM (Node Package Module)
    • Libuv : gère des opérations asynchrones et de la boucle d'événements
    • OpenSSL : ajoute une couche de sécurité réseau TLS/SSL
    • Zlib : compresse/décompresse les fichiers, requêtes, etc.
    • TCP, UDP, HTTP, QUIC: modules qui gèrent les protocoles de communication TCP/UDP
  • Les autres modules au coeur du fonctionnement de Node (core modules)
    • fs : gestion des fichiers
    • http / https : serveur web
    • url : formatage d’URL
    • path : gestion des chemins
    • os : informations sur le système d’exploitation
    • stream : gestion des flux de données (chunk, paquets)
    • util : fonctions utilitaires
Doc. liste exhautive dépendances Node
Chapitre 10 · Bonus : Node.js et autres Web APIs
NodeEtAutresAPIs.introduction()

Introduction à la programmation serveur avec Node.js (modules http, path et fs)

Faire 1 / 3
Chapitre 10 · Bonus : Node.js et autres Web APIs
NodeEtAutresAPIs.programmation()

Canvas / SVG

Comprendre 2 / 3

2 éléments graphiques natives pour la création ou la restitution du contenu image

API Canvas SVG (Scalable Vector Graphics)
Principe Basé sur des pixels (Mode immédiat / Bitmap) Basé sur le DOM (XML/Vectoriel)
Manipulation Rendu effectué via le code JS Éléments ciblables via CSS et le DOM
Performance La performance est stable avec un volume croissant (nombre d'objets croissant) Baisse quand le nombre de nœuds du DOM augmente
Redimensionnement Perte de qualité (netteté) Pas de perte de qualité
Gestion des événements du DOM (greffer le survol ou le clic sur l'élément) Non Oui
Usages Jeux vidéo, 3D, retouche photo, animations complexes Graphiques, logos, icônes, cartes
Chapitre 10 · Bonus : Node.js et autres Web APIs
NodeEtAutresAPIs.canvasVsSVG()

Canvas / SVG

Faire 2 / 3

<!DOCTYPE html>
<html lang="fr">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>CANVAS</title>
</head>
<body>
<canvas width="480" height="360"></canvas>
<script>
  const canvas = document.querySelector("canvas");
  const ctx = canvas.getContext("2d");

  ctx.fillStyle = "orange";
  ctx.fillRect(10, 10, 100, 100);
</script>
</body>
</html>
              

<!DOCTYPE html>
<html lang="fr">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>SVG</title>
</head>
<body>
  <svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 512 512">
    <!-- Icon from selfh.st/icons by selfh.st - https://github.com/selfhst/icons/blob/main/LICENSE -->
    <path fill="#f7df1e" d="M0 0h512v512H0z"/>
    <path d="M343.9 400c10.3 16.8 23.7 29.2 47.5 29.2c19.9 0 32.7-10 32.7-23.7c0-16.5-13.1-22.3-35-31.9l-12-5.2c-34.7-14.8-57.8-33.3-57.8-72.5c0-36.1 27.5-63.6 70.5-63.6c30.6 0 52.6 10.6 68.4 38.5l-37.5 24.1c-8.2-14.8-17.1-20.6-31-20.6c-14.1 0-23 8.9-23 20.6c0 14.4 8.9 20.3 29.6 29.2l12 5.2c40.9 17.5 64 35.4 64 75.6c0 43.3-34 67-79.7 67c-44.7 0-73.5-21.3-87.7-49.2zM174 404.2c7.6 13.4 14.4 24.7 31 24.7c15.8 0 25.8-6.2 25.8-30.2V235.1h48.1v164.2c0 49.8-29.2 72.5-71.8 72.5c-38.5 0-60.8-19.9-72.2-43.9z"/>
  </svg>
</body>
</html>
              
Chapitre 10 · Bonus : Node.js et autres Web APIs
NodeEtAutresAPIs.programmation()

Page visibility API

Comprendre 3 / 3
  • Permet d'économiser de la batteroe et du CPU côté client lorsque l'application n'est plus visible au premier plan par l'utilisateur
  • Les traitements coûteux en ressource tels que les timers (setTimeout, setInterval), animations et les requêtes d'API externes peuvent être mise en pause lorsque l'application passe en arrière plan
  • Comment l'API visibility fonctionne ?
    • La propriété document.visibilityState peut prendre 2 valeurs, hidden ou visible
    • L'événement visibilitychange détecte le changement du passage de l'écran en arrière-plan ou premier-plan
    • La callback de l'événement précédent se déclenche, c'est ici que vous agir pour
Doc. visibility API
Chapitre 10 · Bonus : Node.js et autres Web APIs
NodeEtAutresAPIs.programmation()

Page visibility API

Faire 3 / 3

let animationId = null;
let socket = null;

// --- 1. GESTION ANIMATION ---
function draw() {
  console.log("L'animation tourne...");
  animationId = requestAnimationFrame(draw);
}

function startAnimation() {
  if (!animationId) draw();
}

function stopAnimation() {
  if (animationId) {
    cancelAnimationFrame(animationId);
    animationId = null;
    console.log("Animation stoppée.");
  }
}

// --- 2. GESTION WEBSOCKET ---
function connectWebSocket() {
  if (!socket || socket.readyState === WebSocket.CLOSED) {
    socket = new WebSocket("wss://echo.websocket.org");
    socket.onopen = () => console.log("WebSocket connecté.");
    socket.onmessage = (event) => console.log("Données reçues :", event.data);
    socket.onclose = () => console.log("WebSocket déconnecté.");
  }
}

function disconnectWebSocket() {
  if (socket && socket.readyState === WebSocket.OPEN) {
    socket.close();
    console.log("Demande de déconnexion WebSocket envoyée.");
  }
}

// --- 3. L'API PAGE VISIBILITY ---
function handleVisibilityChange() {
  if (document.visibilityState === "hidden") {
    // L'utilisateur a quitté l'onglet : on coupe tout pour économiser les ressources
    stopAnimation();
    disconnectWebSocket();
  } else if (document.visibilityState === "visible") {
    // L'utilisateur revient sur l'onglet : on relance tout
    startAnimation();
    connectWebSocket();
  }
}

// Écouteur d'événement sur le changement de visibilité de la page
document.addEventListener("visibilitychange", handleVisibilityChange);

// Lancement initial au chargement de la page
startAnimation();
connectWebSocket();

              
Doc. requestAnimationFrame() Doc. cancelAnimationFrame() API Doc. Websocket
Exercice

Atelier 10.1

Bonus : Node.js et autres Web APIs
Correction exercice

Correction Atelier 10.1

Bonus : Node.js et autres Web APIs
Fin

Merci.

vous savez programmer en JavaScript en utilisant les concepts avancés du langage de programmation.

Cours.fin()

Avec Glodie Tshimini

Ce support de cours est protégé par le droit d'auteur.

Toute reproduction, représentation, diffusion ou rediffusion, totale ou partielle, sur quelque support que ce soit, est strictement interdite sans l'accord express de l'auteur.

© Glodie Tshimini, 2026 - Tous droits réservés.