Apprendre HTML CSS JavaScript et TypeScript

Tous les éléments HTML, propriétés CSS, cours JavaScript et TypeScript avec exemples dépliants et explications détaillées. Cliquez sur chaque carte pour voir le rôle, les détails et le code.

80+
Eléments HTML
30+
Propriétés CSS
40+
Concepts JavaScript
20+
Concepts TypeScript

Structure de base

Les éléments fondamentaux qui composent la structure de toute page HTML. Cliquez pour développer.

<!DOCTYPE> Déclaration du type de document Indique au navigateur la version HTML
Rôle : Doit être la toute première ligne du document. Indique qu'il s'agit d'un document HTML5. Sans cette déclaration, le navigateur passe en mode "quirks" et interprète le CSS différemment.

Important : Ce n'est pas une balise HTML mais une instruction de traitement.
<!DOCTYPE html> <html lang="fr"> <head>...en-tête...</head> <body>...contenu...</body> </html>
<html> Elément racine Conteneur principal de toute la page
Rôle : Elément racine qui englobe tout le contenu. L'attribut lang définit la langue — essentiel pour l'accessibilité (lecteurs d'écran) et le SEO.

Attributs : lang="fr", lang="en", dir="ltr" (left to right).
<html lang="fr"> <head> <!-- métadonnées --> </head> <body> <!-- contenu visible --> </body> </html>
<head> En-tête du document Métadonnées, styles, scripts
Rôle : Contient les métadonnées du document. Le contenu n'est pas affiché dans la page visible — il informe le navigateur et les moteurs de recherche.

Contient : <title>, <meta>, <link>, <style>, <script>.
<head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width"> <title>NovaDash</title> <link rel="stylesheet" href="style.css"> </head>
<body> Corps du document Contenu visible de la page
Rôle : Contient tout le contenu visible de la page. Un seul <body> par document.

Evénements JS : Préférez document.addEventListener('DOMContentLoaded', ...) plutôt que l'attribut onload.
<body> <header>...</header> <main> <h1>Bienvenue</h1> <p>Contenu...</p> </main> <footer>...</footer> </body>
<div> Division générique (block) Conteneur block sans sémantique
Rôle : Conteneur générique de type block. Utilisé pour regrouper des éléments pour le CSS.

Quand utiliser : Pour les regroupements purement stylistiques. Préférez les balises sémantiques (<section>, <article>) quand le contenu a un sens.
<div class="card-grid"> <div class="card"> <div class="card-header">...</div> <div class="card-body">...</div> </div> </div>
<span> Conteneur générique (inline) Conteneur inline sans sémantique
Rôle : Conteneur inline (en ligne dans le texte). Sert à cibler une portion de texte pour lui appliquer un style CSS ou une action JS sans créer de nouveau bloc.

Équivalent du <div> : Le <div> est block, le <span> est inline. Même règle : pas de valeur sémantique, donc privilégier les balises spécifiques quand c'est possible.
<p>Prix : <span class="price">29 E</span>/mois</p> <p>Statut : <span class="badge green">Actif</span></p> /* CSS */ .price { color: var(--cyan); font-weight: 700; } .badge { padding: 2px 8px; border-radius: 999px; }

Texte & Titres

Eléments pour structurer le texte et mettre en forme le contenu textuel. Cliquez pour développer.

h1 — h6 Titres hiérarchiques Structurent le contenu en 6 niveaux
Rôle : De h1 (plus important) à h6 (moins important). Créent la hiérarchie du document. Un seul h1 par page pour le SEO — c'est le titre principal.

SEO : Google utilise ces balises pour comprendre la structure. Ne sautez pas de niveaux (h1 → h3 sans h2). N'utilisez pas les titres pour leur taille visuelle — utilisez CSS pour ça.
<h1>Titre de la page</h1>
<h2>Section principale</h2>
<h3>Sous-section</h3>
<h4>Point de détail</h4>
<!-- h5, h6 rarement nécessaires -->
<p> Paragraphe Bloc de texte avec espacement automatique
Rôle : Définit un paragraphe de texte. Élément de type block — crée automatiquement un espace avant et après lui. C'est l'élément texte le plus utilisé.

Ne pas faire : Ne jamais utiliser des <br> répétés pour créer de l'espace entre du texte. Utiliser plusieurs <p> + CSS margin-bottom à la place.
<p>Premier paragraphe de l'article.</p>

<p>Deuxième paragraphe avec <strong>texte
  important</strong> et <em>emphase</em>.</p>
<strong> Importance forte Gras avec valeur sémantique
Rôle : Indique un texte d'importance forte. Affiché en gras. Les lecteurs d'écran l'annoncent avec plus d'insistance.

Différence <b> : <b> est purement visuel. <strong> transmet une importance sémantique. Utilisez <strong> pour les avertissements, prix, termes clés.
<p><strong>Attention :</strong> Action irréversible.</p>

<p>Prix : <strong>29 €</strong>/mois</p>
<em> Emphase italique Accentue un mot avec valeur sémantique
Rôle : Met l'emphase sur un texte (affiché en italique). A une valeur sémantique — les lecteurs d'écran changent le ton de lecture pour ce mot.

Différence <i> : <i> est purement visuel (italique stylistique). <em> = accentuation orale. Utilisez <i> pour les termes étrangers, titres d'œuvres, termes techniques.
<p>Je n'ai <em>jamais</em> dit ça.</p>
<p>L'opéra <i>La Traviata</i></p>
<b> / <u> / <s> Gras, Souligné, Barré Formatage visuel sans valeur sémantique forte
<b> : Texte en gras sans importance sémantique. Pour les mots-clés dans un article, noms de produits.

<u> : Souligné. Utilisé pour les annotations (ex: fautes orthographiques), erreurs dans un texte. Évitez d'utiliser pour des liens — ça prête à confusion.

<s> : Barré. Indique un contenu plus pertinent (ex: ancien prix).
<p><b>Nouveau</b> : produit phare</p>
<p><u>ereur</u> detectée</p>
<p><s>59 €</s><strong>29 €</strong></p>
<mark> Surligneur Met en évidence un texte pertinent
Rôle : Surligne le texte (jaune par défaut). Utilisé pour mettre en évidence un passage pertinent dans un contexte de recherche — comme les résultats de recherche qui surlignent le terme recherché.

Personnalisation : mark { background: var(--cyan); color: #000; }
<p>Résultats pour "<mark>JavaScript</mark>"</p>

<p>Voir la section <mark>3.2</mark> pour plus de détails.</p>
<small> Texte en petit Mentions légales, notes de bas de page
Rôle : Réduit la taille du texte d'un niveau. Sémantiquement utilisé pour les mentions légales, copyrights, avertissements et annotations secondaires.

Usage SaaS typique : Conditions de vente, mentions RGPD, prix avec astérisques, disclaimers.
<div class="price">
  <strong>29 €</strong>/mois
  <small>TVA incluse, sans engagement</small>
</div>
<code> + <pre> Code inline & Bloc de code Afficher du code source
<code> : Fragment de code dans du texte, affiché en monospace. Pour mentionner une variable, commande ou valeur.

<pre> : Texte préformaté — conserve tous les espaces et retours à la ligne. Souvent utilisé avec <code> pour les blocs multi-lignes.

Coloration syntaxique : Ajoutez Prism.js ou Highlight.js pour coloriser automatiquement le code.
<!-- Inline -->
<p>Utilisez <code>console.log()</code> pour déboguer.</p>

<!-- Bloc -->
<pre><code class="language-js">
const x = 42;
console.log(x); // 42
</code></pre>
<blockquote> Citation longue Bloc de citation d'une source externe
Rôle : Indique que le contenu est une citation d'une autre source. Affiché indenté par défaut. L'attribut cite contient l'URL de la source (utile pour le SEO et l'accessibilité).

Composition : Associez-le à <cite> pour nommer l'auteur/source, et <p> pour le texte.
<figure>
  <blockquote cite="https://...">
    <p>Coder, c'est résoudre des problèmes
    élégamment.</p>
  </blockquote>
  <figcaption><cite>Martin Fowler</cite></figcaption>
</figure>
<abbr> Abréviation Signification complète au survol
Rôle : Marque une abréviation ou un acronyme. L'attribut title contient la forme développée — affichée en tooltip au survol.

Accessibilité : Essentiel pour les lecteurs d'écran. La première occurrence d'une abréviation dans une page devrait toujours être développée avec <abbr>.
<p>
  <abbr title="HyperText Markup Language">HTML</abbr>
  est le langage de la toile.
</p>
<abbr title="Cascading Style Sheets">CSS</abbr>
<br> / <hr> Saut de ligne & Séparation Éléments auto-fermants de structure
<br> : Force un retour à la ligne. Utiliser uniquement pour les sauts de ligne sémantiquement nécessaires : adresses, poèmes. Jamais pour créer de l'espace (utilisez CSS).

<hr> : Séparateur horizontal thématique. Indique un changement de sujet dans la page. Personnalisable avec CSS (border: none; border-top: 1px solid...).
<!-- Adresse postale -->
<address>
  JLQDev<br>
  12 rue du Code<br>
  75001 Paris
</address>

<hr> <!-- changement de section -->
<sub> / <sup> Indice et Exposant Formules scientifiques et mathématiques
<sub> (subscript) : texte en indice, abaissé sous la ligne de base. Pour formules chimiques (H₂O), indices mathématiques.

<sup> (superscript) : texte en exposant, surélevé. Pour puissances (x²), ordinals (1ᵉʳ), notes de bas de page (réf.¹).
<!-- Chimie -->
<p>Eau : H<sub>2</sub>O</p>

<!-- Mathématiques -->
<p>x<sup>2</sup> + y<sup>2</sup> = z<sup>2</sup></p>

<!-- Ordinal -->
<p>Le 1<sup>er</sup> prix</p>

Listes

Les différents types de listes pour organiser le contenu.

<ul> Liste non ordonnée Liste à puces sans ordre particulier
Rôle : Conteneur d'une liste à puces. Chaque élément est un <li>. Utilisez-la quand l'ordre n'a pas d'importance.

Style CSS : Personnalisez les puces avec list-style-type: disc/circle/square/none, ou créez des puces personnalisées avec ::before.
<ul>
  <li>HTML — Structure</li>
  <li>CSS — Mise en forme</li>
  <li>JavaScript — Interactivité</li>
</ul>
<ol> Liste ordonnée Liste numérotée avec ordre significatif
Rôle : Liste numérotée automatiquement. Utilisez-la quand l'ordre est important : étapes d'un tutoriel, instructions, classements.

Attributs : start (commence à un autre numéro), reversed (ordre décroissant), type (1, A, a, I, i pour le format de numérotation).
<ol>
  <li>Ouvrir le terminal</li>
  <li>Lancer <code>npm install</code></li>
  <li>Démarrer le serveur</li>
</ol>

<!-- Liste commençant à 5 -->
<ol start="5">...</ol>
<li> Élément de liste Item d'une liste ol ou ul
Rôle : Élément enfant direct d'un <ul> ou <ol>. Peut contenir n'importe quel contenu HTML, y compris une liste imbriquée.

Dans ol : L'attribut value permet de forcer le numéro d'un item spécifique.
<ul>
  <li>Item simple</li>
  <li>
    Item avec sous-liste
    <ul>
      <li>Sous-item</li>
    </ul>
  </li>
</ul>
<dl> / <dt> / <dd> Liste de définitions Paires terme / définition
<dl> : Conteneur de la liste de définitions.
<dt> : Terme à définir (term).
<dd> : Définition/description du terme.

Cas d'usage : Glossaires, FAQ, métadonnées (auteur : X, date : Y), caractéristiques de produit, dictionnaires.
<dl>
  <dt>HTML</dt>
  <dd>HyperText Markup Language</dd>

  <dt>CSS</dt>
  <dd>Cascading Style Sheets</dd>
</dl>

Tableaux

Structure complète des tableaux HTML pour afficher des données tabulaires.

<table> Tableau de données Conteneur principal du tableau
Rôle : Conteneur du tableau. À utiliser uniquement pour des données tabulaires — jamais pour la mise en page (on utilise Flexbox/Grid pour ça).

Structure complète : table → caption, thead, tbody, tfoot → tr → th/td. Chaque niveau a un rôle sémantique.
<table>
  <caption>Statistiques 2026</caption>
  <thead>
    <tr><th>Mois</th><th>CA</th></tr>
  </thead>
  <tbody>
    <tr><td>Janvier</td><td>12 000 €</td></tr>
  </tbody>
</table>
<thead> / <tbody> / <tfoot> Sections du tableau Regroupement sémantique des lignes
<thead> : En-tête — contient les titres des colonnes (<th>). Répété sur chaque page imprimée.

<tbody> : Corps — contient les données. Scrollable indépendamment avec CSS (overflow-y: auto).

<tfoot> : Pied — contient les totaux, résumés. Affiché en bas, mais peut être déclaré avant <tbody> en HTML.
<table>
  <thead><tr>
    <th scope="col">Produit</th>
    <th scope="col">Prix</th>
  </tr></thead>
  <tfoot><tr>
    <td>Total</td><td>290 €</td>
  </tr></tfoot>
</table>
<th> / <td> Cellules de tableau En-tête et données avec fusion possible
<th> : Cellule d'en-tête. Gras et centré par défaut. L'attribut scope="col" ou scope="row" améliore l'accessibilité pour les lecteurs d'écran.

<td> : Cellule de données. Fusion avec colspan (fusionne des colonnes) ou rowspan (fusionne des lignes).
<tr>
  <th scope="row">Janvier</th>
  <td>12 000 €</td>
  <td>+15%</td>
</tr>

<!-- Fusion de 3 colonnes -->
<td colspan="3">Sous-total</td>
<!-- Fusion de 2 lignes -->
<td rowspan="2">Groupe A</td>

Formulaires

Tous les éléments pour créer des formulaires interactifs.

<form> Formulaire Conteneur qui gère l'envoi des données
Rôle : Définit un formulaire et comment ses données sont envoyées.

Attributs :
action : URL de destination (serveur qui reçoit les données)
method : GET (dans l'URL, visible) ou POST (dans le body, caché)
enctype : multipart/form-data obligatoire pour les fichiers
novalidate : désactive la validation native
<form
  action="/api/register"
  method="POST"
  enctype="multipart/form-data"
>
  <!-- champs -->
  <button type="submit">Envoyer</button>
</form>
<input> Champ de saisie L'élément formulaire le plus polyvalent
Rôle : Crée un champ de saisie. Le type détermine complètement l'apparence et le comportement.

Types courants : text, email, password, number, tel, url, date, search, file, checkbox, radio, range, color, hidden, submit.

Attributs clés : placeholder, required, disabled, readonly, min/max, pattern, autocomplete.
<input type="email"
  name="email"
  placeholder="votre@email.com"
  required
  autocomplete="email"
>

<input type="range" min="0" max="100" step="5">
<input type="color" value="#00d2ff">
<label> Étiquette de champ Associe un texte à un champ — essentiel
Rôle : Décrit un champ de formulaire. Cliquer sur le label active le champ associé — améliore l'ergonomie (zone de clic plus grande) et l'accessibilité.

Association : Via l'attribut for qui correspond à l'id du champ, ou en englobant directement le champ.
<!-- Méthode 1 : attribut for/id -->
<label for="email">Email *</label>
<input type="email" id="email" name="email">

<!-- Méthode 2 : englobant -->
<label>
  Mot de passe
  <input type="password" name="pwd">
</label>
<textarea> Zone de texte multiligne Saisie de texte long
Rôle : Champ de texte multi-lignes redimensionnable. Contrairement à <input>, il a une balise fermante et peut contenir une valeur par défaut entre ses balises.

Redimensionnement : Contrôlé en CSS avec resize: none / vertical / horizontal / both.
<label for="msg">Votre message</label>
<textarea
  id="msg"
  name="message"
  rows="6"
  placeholder="Décrivez votre besoin..."
  maxlength="500"
></textarea>
<select> + <option> Menu déroulant Sélection parmi une liste d'options
<select> : Crée le menu déroulant. L'attribut multiple permet la sélection multiple (avec Ctrl/Cmd).

<option> : Chaque choix. L'attribut value est la valeur envoyée au serveur (différente du texte affiché).

<optgroup> : Groupe des options en catégories visuelles.
<select name="pays" id="pays">
  <option value="">-- Choisir --</option>
  <optgroup label="Europe">
    <option value="fr">France</option>
    <option value="de">Allemagne</option>
  </optgroup>
</select>
<button> Bouton Élément cliquable polyvalent
Rôle : Bouton cliquable. Plus flexible que <input type='button'> car il peut contenir du HTML (icônes, badges, etc.).

Types :
type='submit' : soumet le formulaire (défaut dans un form)
type='button' : ne soumet pas — action via JS
type='reset' : réinitialise tous les champs
<!-- Soumission -->
<button type="submit">
  Créer un compte
</button>

<!-- Action JS avec icône -->
<button type="button" onclick="toggle()">
  <svg>...</svg> Menu
</button>
<fieldset> + <legend> Groupe de champs Encadre et nomme un groupe de champs liés
<fieldset> : Groupe des champs logiquement liés avec une bordure. Utile pour les formulaires longs et complexes.

<legend> : Titre du groupe de champs — affiché dans la bordure du fieldset. Essentiel pour l'accessibilité.
<fieldset>
  <legend>Informations personnelles</legend>
  <label for="prenom">Prénom</label>
  <input type="text" id="prenom" name="prenom">
  <label for="nom">Nom</label>
  <input type="text" id="nom" name="nom">
</fieldset>
<progress> / <meter> Barre de progression et jauge Représentations visuelles de valeurs
<progress> : Barre de progression d'une tâche. Sans value, affiche une animation indéterminée.

<meter> : Jauge pour une valeur dans un intervalle connu (disque, score, température). Colore automatiquement selon low, high, optimum.
<!-- Progression de téléchargement -->
<progress value="70" max="100">70%</progress>

<!-- Espace disque utilisé -->
<meter
  value="7" min="0" max="10"
  low="3" high="8" optimum="5"
>7 Go / 10 Go</meter>
<datalist> Suggestions d'autocomplétion Liste de suggestions native pour un input
Rôle : Fournit une liste de suggestions pour un <input>. Le lien se fait via l'attribut list de l'input qui doit correspondre à l'id du datalist.

Différence avec select : L'utilisateur peut saisir n'importe quelle valeur — les options ne sont que des suggestions, pas des contraintes.
<label for="framework">Framework</label>
<input
  id="framework"
  list="frameworks"
  placeholder="Tapez ou choisissez..."
>
<datalist id="frameworks">
  <option value="React">
  <option value="Angular">
  <option value="Vue.js">
</datalist>

Eléments Sémantiques

Les balises sémantiques HTML5 qui améliorent le SEO et l'accessibilité.

<header> En-tête de page ou section Logo, navigation, titre principal
Rôle : En-tête d'une page ou d'une section. Peut être utilisé plusieurs fois dans une page (chaque <article> peut avoir son propre <header>).

Contenu typique : Logo, navigation principale, barre de recherche, titre de section, breadcrumbs.
<header class="site-header">
  <a href="/" class="logo">NovaDash</a>
  <nav>...</nav>
  <button>Connexion</button>
</header>
<nav> Zone de navigation Liens de navigation principaux
Rôle : Identifie une zone de navigation principale. Pas besoin de l'utiliser pour tous les groupes de liens — seulement pour les navigations majeures (menu principal, sidebar, breadcrumbs).

Multiple nav : Si vous en avez plusieurs, utilisez aria-label pour les différencier.
<nav aria-label="Navigation principale">
  <ul>
    <li><a href="/">Accueil</a></li>
    <li><a href="/tarifs">Tarifs</a></li>
    <li><a href="/blog">Blog</a></li>
  </ul>
</nav>
<main> Contenu principal Zone de contenu unique de la page
Rôle : Marque le contenu principal et unique de la page. Un seul <main> par page. Les lecteurs d'écran permettent de sauter directement au <main>.

Ne doit pas contenir : Les éléments répétés sur plusieurs pages comme header, sidebar, footer, navigation.
<body>
  <header>...</header>
  <nav>...</nav>
  <main>
    <h1>Dashboard</h1>
    <!-- Contenu unique de la page -->
  </main>
  <footer>...</footer>
</body>
<section> Section thématique Regroupe du contenu lié sous un même thème
Rôle : Regroupe du contenu thématiquement lié. Devrait toujours avoir un titre (<h2> à <h6>).

Quand utiliser section vs div : <section> si le contenu serait listable dans un sommaire. <div> pour du groupement purement stylistique.
<main>
  <section id="features">
    <h2>Fonctionnalités</h2>
    <div class="features-grid">...</div>
  </section>
  <section id="pricing">
    <h2>Tarifs</h2>...
  </section>
</main>
<article> Contenu autonome Contenu redistribuable indépendamment
Rôle : Contenu autonome et redistribuable — qui aurait du sens sorti de son contexte (blog post, commentaire, tweet, carte produit, widget météo).

Test : Ce contenu serait-il sensé dans un feed RSS ou partagé sur les réseaux sociaux ? Si oui → <article>.
<section class="blog">
  <h2>Derniers articles</h2>
  <article>
    <h3>TypeScript pour débutants</h3>
    <p>...</p>
    <footer>
      <time datetime="2026-02-22">22 fév 2026</time>
    </footer>
  </article>
</section>
<aside> Contenu secondaire Sidebar, widgets, infos complémentaires
Rôle : Contenu tangentiellement lié au contenu principal — qui enrichit sans en faire partie. Dans le contexte d'un article : notes connexes, biographie de l'auteur, publicités. Dans le contexte d'une page : sidebar.

Attention : Ce n'est pas uniquement pour les sidebars — un bloc de contenu connexe dans un article est aussi un <aside>.
<div class="layout">
  <main>...</main>
  <aside class="sidebar">
    <h3>Articles liés</h3>
    <ul>...</ul>
    <h3>Newsletter</h3>
    <form>...</form>
  </aside>
</div>
<footer> Pied de page ou section Copyright, liens, contacts
Rôle : Pied d'une page ou d'une section. Comme <header>, peut être utilisé plusieurs fois (ex: chaque article a son footer avec auteur/date).

Contenu typique : Copyrights, liens légaux, coordonnées, sitemap, réseaux sociaux.
<footer class="site-footer">
  <div class="footer-links">
    <a href="/privacy">Confidentialité</a>
    <a href="/terms">CGU</a>
  </div>
  <p><small>© 2026 JLQDeveloppement</small></p>
</footer>
<time> Date et heure Dates lisibles par les machines
Rôle : Représente une date/heure de manière lisible par l'humain ET par la machine. L'attribut datetime contient la valeur dans un format standardisé (ISO 8601).

Formats datetime : 2026-02-22 (date), 14:30 (heure), 2026-02-22T14:30:00 (datetime), PT2H30M (durée).
<article>
  <h2>Lancement TypeScript 6</h2>
  <p>Publié le
    <time datetime="2026-02-22">
      22 février 2026
    </time>
  </p>
</article>
<details> + <summary> Widget dépliable natif Accordéon sans JavaScript
<details> : Crée un widget dépliable/repliable natif, sans JavaScript. L'attribut open le rend ouvert par défaut.

<summary> : Le titre cliquable visible quand le widget est fermé. Doit être le premier enfant de <details>.
<details>
  <summary>Comment résilier ?</summary>
  <p>Rendez-vous dans Paramètres → Abonnement → Résilier.</p>
</details>

<!-- Ouvert par défaut -->
<details open>
  <summary>FAQ ouverte</summary>
  <p>Réponse visible dès le chargement.</p>
</details>

Head & Meta

Métadonnées, SEO, Open Graph et tout ce qui va dans le <head>.

<title> Titre de la page Onglet navigateur + résultats Google
Rôle : Définit le titre affiché dans l'onglet du navigateur et dans les résultats de recherche Google (SERP). C'est l'un des éléments SEO les plus importants.

Bonnes pratiques : 50-60 caractères max, format Mot-clé principal — Nom du site. Unique sur chaque page.
<head>
  <title>Tableau de bord — NovaDash</title>

  <!-- Pour page d'article -->
  <title>TypeScript pour débutants : le guide complet 2026 — JLQDev</title>
</head>
<meta charset> Encodage des caractères Toujours UTF-8 en premier
Rôle : Définit l'encodage des caractères du document. Doit être UTF-8 pour supporter tous les caractères (accents, emojis, caractères asiatiques, etc.).

Position : Doit être la toute première balise dans le <head>. Si absent, le navigateur devine l'encodage, ce qui peut causer des problèmes d'affichage.
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>...</title>
</head>
<meta viewport> Viewport responsive Indispensable pour le mobile
Rôle : Contrôle le viewport sur les appareils mobiles. Sans cette balise, les mobiles affichent la page à la largeur d'un écran desktop et la réduisent.

content : width=device-width = largeur du viewport = largeur de l'écran. initial-scale=1.0 = zoom initial à 100%.
<meta name="viewport"
  content="width=device-width, initial-scale=1.0">

<!-- Désactiver le zoom utilisateur (déconseillé) -->
<meta name="viewport"
  content="width=device-width, initial-scale=1.0,
          maximum-scale=1.0, user-scalable=no"
>
<meta description> Description SEO Texte affiché sous le titre dans Google
Rôle : Description de la page affichée sous le titre dans les résultats Google. Pas un facteur de ranking direct, mais impacte le taux de clic (CTR).

Bonnes pratiques : 150-160 caractères max, inclure les mots-clés naturellement, appel à l'action, unique par page.
<meta name="description"
  content="NovaDash est un tableau de bord
        financier tout-en-un. Gérez votre
        budget, crypto et investissements.
        Essai gratuit 30 jours."
>
<meta og:*> Open Graph (réseaux sociaux) Contrôle l'aperçu lors des partages
Rôle : Balises Open Graph développées par Facebook, maintenant standard sur tous les réseaux sociaux. Contrôlent l'image, le titre et la description affichés quand la page est partagée.

Indispensable : Sans ces balises, les réseaux sociaux choisissent aléatoirement une image de la page.
<meta property="og:title" content="NovaDash — FinTech SaaS">
<meta property="og:description" content="...">
<meta property="og:image" content="https://.../og.png">
<meta property="og:url" content="https://novadash.fr">
<meta property="og:type" content="website">
<!-- Twitter/X spécifique -->
<meta name="twitter:card" content="summary_large_image">
<link> Lien vers ressource externe CSS, favicon, fonts, preload
Rôle : Lie le document HTML à des ressources externes (feuilles de style, favicon, polices, manifeste PWA).

rel courants : stylesheet, icon, preconnect, preload, canonical, manifest.
<!-- Feuille de styles -->
<link rel="stylesheet" href="style.css">

<!-- Favicon -->
<link rel="icon" href="/favicon.ico">

<!-- Préconnexion Google Fonts -->
<link rel="preconnect" href="https://fonts.googleapis.com">

<!-- URL canonique SEO -->
<link rel="canonical" href="https://...">

Box Model

Le modèle de boîte définit comment chaque élément occupe l'espace.

width / height Dimensions de l'élément Taille en px, %, vw/vh, auto ou fit-content
Rôle : Définissent la taille de la zone de contenu. Avec box-sizing: border-box, ils incluent padding et bordure.

Valeurs modernes :
min-content : taille minimale que le contenu peut prendre
max-content : taille que prendrait le contenu sans contrainte
fit-content : s'adapte au contenu sans dépasser le conteneur
/* Fixe */
width: 300px;
height: 200px;

/* Responsive */
width: min(90%, 1200px);
height: 100vh;

/* Adaptatif */
width: fit-content;
min-width: 200px;
max-width: 600px;
padding Espace intérieur Entre le contenu et la bordure
Rôle : Crée de l'espace intérieur entre le contenu et la bordure. N'est jamais transparent — prend la couleur de fond.

Raccourcis :
padding: 10px = 4 côtés identiques
padding: 10px 20px = haut/bas | gauche/droite
padding: 10px 20px 15px 25px = haut | droite | bas | gauche (sens horaire)
/* 4 côtés */
padding: 16px;

/* Vertical | Horizontal */
padding: 12px 24px;

/* Individuel */
padding-top: 20px;
padding-inline: 16px; /* gauche+droite */
padding-block: 8px; /* haut+bas */
margin Espace extérieur Autour de l'élément, permet le centrage
Rôle : Crée de l'espace entre l'élément et ses voisins. Transparence toujours (révèle l'arrière-plan du parent).

Astuces :
margin: 0 auto : centre horizontalement un bloc avec width
margin-top: auto : pousse vers le bas dans un flex column
• Marges qui collapsent : marges verticales adjacentes fusionnent
/* Centrage horizontal */
width: 800px;
margin: 0 auto;

/* Pousser vers le bas en flex */
margin-top: auto;

/* Supprimer le margin défaut */
margin: 0;
border Bordure Trait autour de l'élément
Rôle : Raccourci pour border-width, border-style et border-color. La bordure s'ajoute à la taille de l'élément (sauf avec box-sizing: border-box).

Styles : solid, dashed, dotted, double, groove, none.
/* Raccourci */
border: 1px solid rgba(255,255,255,0.1);

/* Bordure individuelle */
border-bottom: 2px solid var(--cyan);

/* Bordure avec dégradé */
border: 1px solid transparent;
background-image: linear-gradient(#000, #000),
  linear-gradient(to right, cyan, violet)
;
background-clip: padding-box, border-box;
border-radius Coins arrondis Arrondit les angles de l'élément
Rôle : Arrondit les coins de l'élément. Peut créer des cercles parfaits (50%), des pilules (999px), ou des formes asymétriques.

Formes courantes :
4px : légère courbure (cards)
8-16px : fortement arrondi
999px : pilule (badges, boutons)
50% : cercle parfait
/* Card */
border-radius: 12px;

/* Badge/Pill */
border-radius: 999px;

/* Avatar circulaire */
border-radius: 50%;

/* Asymétrique */
border-radius: 20px 4px 20px 4px;
box-sizing Modèle de taille border-box recommandé — toujours
Problème : Par défaut (content-box), un élément de width: 100px + padding: 20px fait 140px en réalité.

Solution : border-box inclut padding et border dans la taille déclarée — l'élément fait exactement width: 100px même avec du padding.
/* ✅ Bonne pratique globale */
*, *::before, *::after {
  box-sizing: border-box;
}

/* Résultat : width: 200px reste 200px */
.card {
  width: 200px;
  padding: 20px; /* ne s'ajoute pas */
}
box-shadow Ombre portée Ombres simples ou multiples (glow)
Syntaxe : x y blur spread color. La valeur inset crée une ombre intérieure.

Effets SaaS :
• Ombre douce : 0 4px 20px rgba(0,0,0,0.3)
• Glow néon : 0 0 20px rgba(0,210,255,0.5)
• Multiple : séparées par virgule
/* Ombre douce */
box-shadow: 0 4px 20px rgba(0,0,0,0.3);

/* Glow néon cyan */
box-shadow: 0 0 30px rgba(0,210,255,0.4);

/* Ombres multiples */
box-shadow:
  0 2px 4px rgba(0,0,0,0.2),
  0 8px 30px rgba(0,210,255,0.3);

/* Inset (intérieur) */
box-shadow: inset 0 2px 4px rgba(0,0,0,0.5);
overflow Gestion du débordement Que faire quand le contenu dépasse
Rôle : Définit ce qui se passe quand le contenu dépasse les dimensions du conteneur.

Valeurs :
visible : dépasse (défaut)
hidden : coupe le débordement — utile pour border-radius sur des images
scroll : toujours visible les scrollbars
auto : scrollbars uniquement si nécessaire
/* Couper le dépassement */
overflow: hidden;

/* Zone scrollable verticalement */
height: 400px;
overflow-y: auto;

/* Couper le texte (avec ellipsis) */
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;

Typographie CSS

Toutes les propriétés pour contrôler la police, la taille et l'apparence du texte.

font-family Police de caractères Définit la fonte avec fallbacks
Rôle : Définit la ou les polices à utiliser. Toujours inclure des polices de secours. L'ordre compte : si la première n'est pas disponible, la suivante est utilisée.

Familles génériques : serif, sans-serif, monospace, cursive, fantasy.
/* Depuis Google Fonts */
font-family: 'Outfit', 'Helvetica Neue', sans-serif;

/* Monospace pour le code */
font-family: 'JetBrains Mono', 'Consolas', monospace;

/* Variable system font stack */
font-family: system-ui, -apple-system, sans-serif;
font-size Taille du texte px, rem, em ou clamp() pour la fluidité
Rôle : Définit la taille du texte.

Recommandations :
rem : relatif à la taille racine (root). 1rem = 16px par défaut. Respecte les préférences de zoom utilisateur.
em : relatif au parent — peut créer des effets en cascade
clamp(min, ideal, max) : taille fluide responsive sans media query
/* Rem recommandé */
font-size: 1rem; /* = 16px */
font-size: 1.25rem; /* = 20px */

/* Fluide : 16px → 32px entre 320px et 1200px */
font-size: clamp(1rem, 2.5vw, 2rem);

/* Grande headline */
font-size: clamp(2rem, 6vw, 5rem);
font-weight Graisse de la police De 100 (ultra-light) à 900 (black)
Valeurs : 100 (Thin), 200, 300 (Light), 400 (Regular/Normal), 500 (Medium), 600 (SemiBold), 700 (Bold), 800 (ExtraBold), 900 (Black).

Disponibilité : Dépend de la police chargée. Si une graisse n'existe pas, le navigateur en simule une autre. Google Fonts permet de choisir les graisses à charger.
/* Texte courant */
font-weight: 400;

/* Semi-bold pour les labels */
font-weight: 600;

/* Bold pour les titres */
font-weight: 700;

/* Ultra pour les grandes headlines */
font-weight: 900;
line-height Hauteur de ligne Espacement vertical entre lignes de texte
Rôle : Définit l'espace vertical entre les lignes. Sans unité, c'est un multiplicateur de font-size — recommandé car il s'adapte à toutes les tailles.

Recommandations :
• Texte courant : 1.5 à 1.7
• Titres : 1.1 à 1.3
• Labels courts : 1
/* Corps de texte */
font-size: 1rem;
line-height: 1.6;

/* Titre serré */
font-size: 3rem;
line-height: 1.15;

/* Bouton (centrage vertical) */
line-height: 1;
letter-spacing Espacement entre lettres Tracking typographique
Rôle : Ajuste l'espace entre les caractères. Positif pour écarter (lettres plus aérées), négatif pour resserrer (titres XXL).

Usages SaaS :
0.1em : labels, badges, tags (caps)
-0.02em : titres volumineux pour compenser l'écartement optique
0.5px : navigation, menus
/* Label en majuscules */
.label {
  text-transform: uppercase;
  font-size: 0.75rem;
  letter-spacing: 0.1em;
}

/* Grande headline resserrée */
h1 {
  font-size: 5rem;
  letter-spacing: -0.03em;
}
text-transform Transformation de casse uppercase, lowercase, capitalize
Rôle : Change la casse du texte via CSS — sans modifier le HTML.

Valeurs :
uppercase : TOUT EN MAJUSCULES
lowercase : tout en minuscules
capitalize : Première Lettre De Chaque Mot
none : texte tel quel
/* Badges / Tags */
.badge {
  text-transform: uppercase;
  letter-spacing: 0.08em;
}

/* Titres de section */
.nav-group-title {
  text-transform: uppercase;
  font-size: 0.65rem;
}
text-shadow Ombre de texte Glow néon et effets typographiques
Rôle : Ajoute une ombre portée au texte. Même syntaxe que box-shadow mais sans spread ni inset.

Effets SaaS :
• Glow néon : ombre floue de la couleur du texte
• Ombres multiples : pour des effets 3D ou de profondeur
/* Glow cyan */
.hero-text {
  color: var(--cyan);
  text-shadow: 0 0 20px rgba(0,210,255,0.5);
}

/* Glow multicolore */
text-shadow:
  0 0 10px #00d2ff,
  0 0 40px #00d2ff,
  0 0 80px rgba(0,210,255,0.3);
white-space / text-overflow Gestion des espaces et dépassement Couper, ellipsis, nowrap
white-space : Contrôle le traitement des espaces et retours à la ligne.

text-overflow : Que faire quand le texte dépasse avec overflow: hidden. ellipsis affiche ....

Pattern ellipsis : Les 3 propriétés doivent être combinées.
/* Ellipsis sur une ligne */
.card-title {
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
}

/* Ellipsis sur N lignes (WebKit) */
.excerpt {
  display: -webkit-box;
  -webkit-line-clamp: 3;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

Layout & Position

Contrôle du flux, du positionnement et du comportement d'affichage.

position Mode de positionnement static, relative, absolute, fixed, sticky
Rôle : Définit comment l'élément se positionne dans le flux.

Valeurs :
static : flux normal (défaut)
relative : décalage par rapport à sa position normale (gardé dans le flux)
absolute : sort du flux, positionné par rapport au parent positionné
fixed : fixé dans le viewport (scrolls pas)
sticky : relatif jusqu'à un seuil, puis fixe
/* Parent de référence */
.parent { position: relative; }

/* Badge positionné */
.badge {
  position: absolute;
  top: -8px; right: -8px;
}

/* Topbar collante */
.topbar {
  position: sticky;
  top: 0;
  z-index: 100;
}
display Type d'affichage La propriété CSS la plus fondamentale
Rôle : Définit le type de rendu de l'élément et son comportement dans le flux.

Valeurs essentielles :
block : pleine largeur, nouvelle ligne
inline : dans le flux du texte
inline-block : inline mais avec dimensions
flex : layout flexbox
grid : layout grille
none : masque complètement (supprime de l'espace)
/* Masquer un élément */
.hidden { display: none; }

/* Centrer contenu */
.center {
  display: flex;
  place-items: center;
}

/* Inline avec taille */
.btn-icon {
  display: inline-flex;
  align-items: center;
  gap: 8px;
}
z-index Ordre d'empilement Contrôle les superpositions
Rôle : Définit l'ordre d'empilement des éléments positionnés (position ≠ static). Valeur plus élevée = au-dessus.

Bonnes pratiques : Utilisez des variables CSS pour une gestion systématique. Évitez les 9999 aléatoires — créez une échelle.
/* Système d'échelle */
:root {
  --z-base: 1;
  --z-dropdown: 10;
  --z-sticky: 100;
  --z-modal: 1000;
  --z-toast: 9999;
}

.modal { z-index: var(--z-modal); }
object-fit Ajustement image/vidéo Contrôle comment le média remplit son conteneur
Rôle : Définit comment une image ou vidéo s'adapte à son conteneur quand les proportions diffèrent.

Valeurs :
cover : remplit tout (peut couper) ✅ le plus utilisé
contain : entier visible (peut laisser des bandes)
fill : étire pour remplir (déforme)
none : taille originale
/* Avatar carré sans déformation */
.avatar {
  width: 48px;
  height: 48px;
  border-radius: 50%;
  object-fit: cover;
  object-position: center top;
}

Effets visuels & Animations

Transformations, filtres, animations @keyframes et transitions.

transform Transformations 2D/3D Déplacer, tourner, agrandir, incliner
Rôle : Applique des transformations géométriques sans affecter le layout (ne déplace pas les autres éléments). Performant car traité par le GPU.

Fonctions : translateX/Y(), translate(x, y), rotate(deg), scale(), skew(), perspective(), et leurs équivalents 3D.
/* Hover élévation */
.card:hover {
  transform: translateY(-4px);
}

/* Spinner rotatif */
@keyframes spin {
  to { transform: rotate(360deg); }
}

/* Scale au clic */
.btn:active {
  transform: scale(0.96);
}
filter Filtres visuels Flou, luminosité, teinte, grayscale
Rôle : Applique des effets de traitement d'image à un élément.

Fonctions : blur(), brightness(), contrast(), grayscale(), hue-rotate(), saturate(), invert(), drop-shadow().
/* Image désaturée au hover */
.logo { filter: grayscale(100%); }
.logo:hover { filter: none; }

/* Glow lumineux */
.icon-glow {
  filter: drop-shadow(0 0 8px var(--cyan));
}

/* Image assombrie */
.hero-bg { filter: brightness(0.4); }
backdrop-filter Flou de l'arrière-plan Effet glassmorphism
Rôle : Applique des filtres sur le contenu derrière l'élément (pas sur l'élément lui-même). Nécessite que l'élément soit semi-transparent pour que l'effet soit visible.

Glassmorphism : La combinaison background: rgba + backdrop-filter: blur crée l'effet verre dépoli.
/* Glassmorphism */
.glass-card {
  background: rgba(255, 255, 255, 0.05);
  backdrop-filter: blur(20px) saturate(180%);
  border: 1px solid rgba(255,255,255,0.1);
}

/* Topbar floutée */
.topbar {
  background: rgba(10,10,18,0.8);
  backdrop-filter: blur(10px);
}
clip-path Découpe de forme Masques géométriques sur les éléments
Rôle : Découpe l'élément selon une forme géométrique. Tout ce qui est en dehors de la forme est invisible.

Formes : circle(), ellipse(), polygon(), inset(), path().
/* Cercle */
.avatar { clip-path: circle(50%); }

/* Hexagone */
.hex {
  clip-path: polygon(
    50% 0%, 100% 25%, 100% 75%,
    50% 100%, 0% 75%, 0% 25%)
;
}

/* Diagonale en bas */
.hero {
  clip-path: polygon(0 0, 100% 0, 100% 90%, 0 100%);
}
@keyframes + animation Animations CSS Définir et appliquer des animations
@keyframes : Définit les étapes d'une animation avec des pourcentages (0%, 50%, 100%) ou des mots-clés (from, to).

animation : Raccourci pour appliquer et configurer l'animation : nom durée timing délai itérations direction fill-mode play-state.
/* Définir le mouvement */
@keyframes fadeInUp {
  from {
    opacity: 0;
    transform: translateY(20px);
  }
  to { opacity: 1; transform: none; }
}

/* Appliquer */
.hero h1 {
  animation: fadeInUp 0.6s ease forwards;
}

/* Spinner */
@keyframes spin { to { transform: rotate(360deg); } }
.loader { animation: spin 1s linear infinite; }
transition Transitions fluides Animer les changements d'état CSS
Rôle : Anime la transition entre deux valeurs CSS (état initial → état hover/focus/active). Plus simple que @keyframes.

Syntaxe : propriété durée timing délai. all anime toutes les propriétés (moins performant).
/* Bouton interactif */
.btn {
  background: var(--cyan);
  transition: background 0.2s ease,
             transform 0.15s ease,
             box-shadow 0.2s ease
;
}
.btn:hover {
  background: var(--cyan-bright);
  transform: translateY(-2px);
  box-shadow: 0 8px 20px rgba(0,210,255,0.4);
}

Flexbox

Le modèle de boîte flexible pour l'alignement unidimensionnel. Incontournable pour les navbars, centrage et distributions.

display: flexActiver FlexboxConteneur flex pour l'alignement des enfants
Rôle : display: flex transforme un élément en conteneur flex. Ses enfants directs deviennent des flex items alignés en ligne par défaut.

Axe principal : Horizontal par défaut (row). L'axe croisé est vertical. Tout l'alignement s'effectue par rapport à ces deux axes.
.container { display: flex; /* axe principal: horizontal */ } /* Les enfants s'alignent en ligne */ <div class="container"> <div>Item 1</div> <div>Item 2</div> <div>Item 3</div> </div>
justify-contentAlignement sur l'axe principalDistribution des items horizontalement
Rôle : Distribue l'espace sur l'axe principal (horizontal en row).

Valeurs clés :
flex-start : tassé à gauche (défaut)
center : centré
flex-end : tassé à droite
space-between : espacés, pas de marge extérieure
space-around : espacés avec demi-marge extérieure
.navbar { display: flex; justify-content: space-between; /* logo | nav | bouton */ } .center { display: flex; justify-content: center; }
align-itemsAlignement sur l'axe croiséDistribution des items verticalement
Rôle : Aligne les items sur l'axe croisé (vertical en row). La combinaison justify-content: center + align-items: center est la façon la plus simple de centrer un élément.

Valeurs : stretch (défaut), center, flex-start, flex-end, baseline.
/* Centrage parfait */ .centered { display: flex; justify-content: center; align-items: center; height: 100vh; } /* Navbar alignement vertical */ .nav { display: flex; align-items: center; gap: 16px; }
flex-directionDirection de l'axe principalHorizontal ou vertical
Rôle : Change la direction de l'axe principal.

Valeurs :
row : horizontal, gauche→droite (défaut)
row-reverse : horizontal, droite→gauche
column : vertical, haut→bas
column-reverse : vertical, bas→haut

Astuce : Avec column, justify-content devient vertical et align-items horizontal.
.sidebar-nav { display: flex; flex-direction: column; gap: 8px; } .card { display: flex; flex-direction: column; justify-content: space-between; height: 100%; }
flex / flex-wrap / gapTaille, retour à la ligne et espacementContrôle complet du comportement flex
flex : Raccourci pour flex-grow flex-shrink flex-basis. flex: 1 = l'item prend tout l'espace disponible.

flex-wrap : wrap autorise le retour à la ligne quand les items débordent. Essentiel pour le responsive.

gap : Espacement entre les items (rem­place les marges).
.layout { display: flex; flex-wrap: wrap; gap: 16px; } .card { flex: 1 1 300px; /* min 300px, grandit pour remplir */ } .sidebar { flex: 0 0 260px; } .main { flex: 1; }

CSS Grid

Mise en page bidimensionnelle (lignes + colonnes). Parfait pour les layouts de pages, dashboards et grilles de cartes.

display: gridActiver CSS GridGrille bidimensionnelle lignes et colonnes
Rôle : CSS Grid est un système de mise en page bidimensionnel (lignes + colonnes). Parfait pour les layouts complexes de pages entières.

Flexbox vs Grid : Flexbox = 1D (une seule direction). Grid = 2D (lignes ET colonnes simultanément). Utilisez les deux ensemble!
.grid { display: grid; grid-template-columns: 1fr 1fr 1fr; grid-template-rows: auto; gap: 24px; } /* 3 colonnes égales sur 6 cartes */ <div class="grid"> <div>Card 1</div> <div>Card 2</div> <div>Card 3</div> </div>
grid-template-columnsDéfinir les colonnesfr, repeat(), minmax() pour layouts responsives
fr (fraction) : Unité qui divise l'espace disponible. 1fr 2fr = 33% + 66%.

repeat() : repeat(3, 1fr) = 3 colonnes égales. repeat(auto-fit, minmax(280px, 1fr)) = grille responsive automatique sans media queries!

minmax() : Définit une taille min et max pour chaque colonne.
/* 3 colonnes égales */ grid-template-columns: repeat(3, 1fr); /* Sidebar + contenu */ grid-template-columns: 260px 1fr; /* Grille responsive automatique! */ grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); /* Dashboard: sidebar + main + panel */ grid-template-columns: 240px 1fr 320px;
grid-column / grid-rowPlacer et étirer un élémentSpan sur plusieurs colonnes ou lignes
Rôle : Contrôle exactement où se place un élément dans la grille et sur combien de colonnes/lignes il s'étale.

Syntaxe : grid-column: 1 / 3 = de la ligne 1 à la ligne 3 (2 colonnes). span 2 = s'étale sur 2 colonnes depuis sa position actuelle.
.hero-banner { grid-column: 1 / -1; /* toute la largeur */ } .featured-card { grid-column: span 2; /* 2 colonnes */ grid-row: span 2; /* 2 lignes */ } .sidebar-widget { grid-column: 3; /* colonne 3 exactement */ grid-row: 1 / 4; /* lignes 1 à 4 */ }
grid-template-areasLayout nommé par zonesVisualiser le layout dans le CSS
Rôle : Définit le layout par des noms visuels. On dessine littéralement la grille avec du texte dans le CSS.

Avantage : Très lisible, idéal pour les layouts de pages. Chaque zone est un string, . = cellule vide.
.app-layout { display: grid; grid-template-areas: "header header header" "sidebar main aside" "footer footer footer"; grid-template-columns: 200px 1fr 280px; } header { grid-area: header; } .sidebar { grid-area: sidebar; } main { grid-area: main; } footer { grid-area: footer; }

Bases & Syntaxe

Les fondamentaux de JavaScript : variables, types, syntaxe de base.

var / let / constDéclaration de variables3 mots-clés pour créer des variables
let : variable modifiable, portée de bloc. C'est le choix par défaut en JS moderne.

const : constante — ne peut pas être réassignée. Utilisez const par défaut et let uniquement si la valeur change. Les tableaux et objets const restent mutables.

var : ancien système, portée de fonction. Evitez-le — hoisting, pas de portée de bloc.
let compteur = 0; compteur = 1; // OK const NOM = "Julien"; // NOM = "Bob"; ❌ TypeError! // const objet : le contenu est mutable const arr = [1, 2]; arr.push(3); // ✓ [1,2,3]
`template`Template LiteralsChaînes avec interpolation et multiligne
Rôle : Les backticks permettent d'insérer des variables et expressions avec ${...}. Supportent les retours à la ligne natifs.

Avantages : Plus lisible que la concaténation avec +. Expressions complexes possibles : ${a > b ? a : b}.
const nom = "Julien", age = 28; // Template literal const msg = `Bonjour ${nom}, tu as ${age} ans`; // Multiligne natif const html = ` <div class="card"> <h2>${nom}</h2> </div> `;
consoleConsole de débogageAfficher des valeurs et mesurer les performances
Rôle : Affiche des valeurs dans la console du navigateur (F12). Outil essentiel pour le débogage.

Variantes : console.warn() (jaune), console.error() (rouge), console.table() (tableau), console.time()/console.timeEnd() (mesure de performance).
console.log("Hello world"); console.warn("Attention !"); console.error("Erreur critique"); console.table([1, 2, 3]); // Mesurer la performance console.time("tri"); arr.sort(); console.timeEnd("tri");

Types de Données

JavaScript a 8 types : 7 primitifs et le type objet.

string Chaîne de caractères Texte délimité par des guillemets ou backticks
Rôle : Type pour le texte. Immuable en JavaScript — toutes les méthodes string retournent une nouvelle chaîne (la chaîne d’origine ne change pas).

Méthodes utiles : .length, .toUpperCase(), .toLowerCase(), .trim(), .includes(), .startsWith(), .split(), .replace(), .slice().

Détails des méthodes :
.length — propriété (pas de parenthèses) : renvoie le nombre de caractères.
.toUpperCase() — renvoie la chaîne en majuscules.
.toLowerCase() — renvoie la chaîne en minuscules.
.trim() — enlève les espaces (et retours ligne) au début et à la fin.
.includes("x") — renvoie true si la sous-chaîne est trouvée (sensible à la casse).
.startsWith("x") — renvoie true si la chaîne commence par ce texte.
.split(sep) — découpe en tableau selon un séparateur (ex : ",", " ").
.replace(a, b) — remplace la première occurrence (ou toutes avec une regex /.../g).
.slice(debut, fin) — extrait une partie (fin exclue). Accepte des index négatifs (ex : -1 = dernier caractère).

Notes : includes et startsWith sont sensibles à la casse : "Julien".includes("jul") vaut false.
const nom = "Julien";
const greeting = `Bonjour ${nom}!`;

nom.length // 6
nom.toUpperCase() // "JULIEN"
nom.toLowerCase() // "julien"

" texte ".trim() // "texte"

nom.includes("ul") // true
nom.startsWith("Ju") // true

"a,b,c".split(",") // ["a","b","c"]
"un deux trois".split(" ") // ["un","deux","trois"]

"Bonjour Julien".replace("Julien", "Marie") // "Bonjour Marie"
"ha ha ha".replace(/ha/g, "ho") // "ho ho ho"

nom.slice(0, 3) // "Jul"
nom.slice(-1) // "n"
number Nombre Entiers et décimaux — même type en JS
Rôle : JavaScript n'a qu'un type numérique (Number) pour les entiers et les décimaux. Précision limitée pour les très grands entiers (utilisez BigInt).

Valeurs spéciales : Infinity, -Infinity, NaN (Not a Number — résultat d'opération invalide).

Math : Math.round(), Math.floor(), Math.ceil(), Math.random(), Math.abs(), Math.max().

Détails des méthodes :
Math.round(x) — arrondit à l’entier le plus proche (0.5 arrondit “vers le haut” côté positif : 2.5 → 3).
Math.floor(x) — arrondit à l’entier inférieur (vers -Infinity) : 3.9 → 3, -1.2 → -2.
Math.ceil(x) — arrondit à l’entier supérieur (vers +Infinity) : 3.1 → 4, -1.2 → -1.
Math.random() — renvoie un nombre pseudo-aléatoire dans [0, 1) (0 inclus, 1 exclu).
Math.abs(x) — valeur absolue : transforme un nombre en positif (ou 0).
Math.max(a, b, ...) — renvoie le plus grand des nombres passés en paramètres (attention : pas directement sur un tableau sans ...).

Astuce : nombre aléatoire entier entre min et max inclus : Math.floor(Math.random() * (max - min + 1)) + min.
const prix = 29.99;
const score = 100;

Number("42") // 42
parseInt("3.7") // 3
parseFloat("3.7") // 3.7
isNaN("abc") // true

Math.round(29.49) // 29
Math.round(29.50) // 30

Math.floor(3.9) // 3
Math.ceil(3.1) // 4
Math.floor(-1.2) // -2
Math.ceil(-1.2) // -1

Math.random() // 0.0 à 0.999...
const de = Math.floor(Math.random() * 6) + 1; // 1 à 6

Math.abs(-10) // 10
Math.max(3, 10, 7) // 10
Math.max(...[3, 10, 7]) // 10
boolean Valeur booléenne true ou false — base de toute logique
Rôle : Représente une valeur logique vrai/faux. Toute valeur en JS est soit true soit false.

Valeurs false : false, 0, -0, 0n, "", null, undefined, NaN. Tout le reste est true (même [] et {})!
const actif = true;
const desactive = false;

// True / False
if ([]) { /* ✅ true! */ }
if (0) { /* ❌ false */ }
if ("") { /* ❌ false */ }

Boolean(0) // false
Boolean("a") // true
Boolean(null) // false
null / undefined Valeurs absentes Absence intentionnelle vs non-initialisé
null : Absence intentionnelle de valeur. Assigné volontairement par le développeur pour indiquer « pas de valeur ».

undefined : Variable déclarée mais pas encore assignée. Retourné par les fonctions sans return, les propriétés inexistantes.

Comparaison : null == undefined est true, mais null === undefined est false.
// undefined : déclaré, non assigné
let user; // undefined
const obj = {};
obj.name; // undefined

// null : intentionnellement vide
let token = null; // pas encore connecté

// Guard clause
if (user === null || user === undefined) {
  // Ou : if (user == null)
}
array [] Tableau Collection ordonnée d'éléments
Rôle : Structure de données pour stocker des listes ordonnées. Les tableaux JS peuvent mélanger des types. L'index commence à 0.

Type : typeof [] retourne "object". Pour tester si c'est un tableau : Array.isArray([])true.
const users = ["Alice", "Bob", "Julien"];

users[0] // "Alice"
users.length // 3
users.at(-1) // "Julien" (dernier)

// Types mixtes (déconseillé mais possible)
const mixed = [1, "hello", true, null];

Array.isArray([]) // true ✅
object {} Objet Collection de paires clé-valeur
Rôle : Structure de données pour des données structurées. Les clés sont des strings (ou Symbols). Les valeurs peuvent être de n'importe quel type, y compris des fonctions (méthodes).

Attention : Les objets sont passés par référence — assigner un objet à une variable ne crée pas une copie!
const user = {
  nom: "Julien",
  age: 28,
  actif: true,
  saluer() { return `Hi ${this.nom}`; }
};

user.nom // "Julien"
user.saluer() // "Hi Julien"

Conditions

Les structures conditionnelles contrôlent le flux d'exécution.

if / elseCondition classiqueExécution conditionnelle du code
Rôle : Exécute un bloc si la condition est vraie (truthy). Chaîner avec else if, terminer par else.

Valeurs falsy : false, 0, "", null, undefined, NaN. Tout le reste est truthy — même [] et {}!
const score = 85; if (score >= 90) { console.log("Excellent"); } else if (score >= 70) { console.log("Bien"); } else { console.log("A améliorer"); }
? : ternaireOpérateur ternaireif/else condense en une expression
Syntaxe : condition ? siVrai : siFaux. Retourne une valeur selon une condition.

Usage : Assignations conditionnelles, affichage conditionnel. Evitez d'imbriquer — lisibilité réduite. Pour des cas complexes, préférez if/else.
const label = age >= 18 ? "Adulte" : "Mineur"; // Affichage conditionnel const badge = actif ? `<span class="green">Actif</span>` : `<span class="red">Inactif</span>`;

Asynchrone

Promises et async/await pour gérer les opérations non-bloquantes.

setTimeout / setInterval Timers Exécuter du code après délai ou répétitivement
setTimeout : Exécute une fonction une fois après un délai (ms). Retourne un ID pour annuler avec clearTimeout(id).

setInterval : Exécute une fonction à intervalles répétitifs. Toujours nettoyer avec clearInterval(id) pour éviter les fuites mémoire.
// Exécuter après 2 secondes
const id = setTimeout(() => {
  console.log("2 secondes écoulées!");
}, 2000);

// Annuler si besoin
clearTimeout(id);

// Répéter toutes les secondes
const timer = setInterval(() => {
  updateClock();
}, 1000);

// Arrêter (ex: au démontage du composant)
clearInterval(timer);
Promise Promesse asynchrone Représente une valeur future
Rôle : Objet représentant l'éventuel résultat d'une opération asynchrone. 3 états : pending (en attente), fulfilled (résolue), rejected (rejetée).

En pratique : Vous créez rarement des Promises manuellement — elles sont retournées par les API (fetch, fs.readFile...). Vous les consommez avec .then/.catch ou async/await.
// Créer une Promise
const p = new Promise((resolve, reject) => {
  setTimeout(() => {
    if (Math.random() > 0.5) resolve("✅ Succès");
    else reject(new Error("❌ Echec"));
  }, 1000);
});

p.then(result => console.log(result))
  .catch(err => console.error(err));
async / await Async/Await Syntaxe moderne pour les Promises
Rôle : Sucre syntaxique sur les Promises qui rend le code asynchrone lisible comme du code synchrone. async transforme une fonction en Promise, await attend la résolution d'une Promise.

Règle : await ne peut être utilisé qu'à l'intérieur d'une fonction async.
// Fonction async
async function loadUser(id) {
  try {
    const res = await fetch(`/api/users/${id}`);
    if (!res.ok) throw new Error("Erreur API");
    const data = await res.json();
    return data;
  } catch (err) {
    console.error("Echec:", err.message);
  }
}
fetch() API fetch Requêtes HTTP modernes et natives
Rôle : API native pour faire des requêtes HTTP (GET, POST, PUT, DELETE...). Retourne une Promise qui se résout avec un objet Response.

Important : fetch ne rejette pas pour les erreurs HTTP (404, 500) — il faut vérifier response.ok. Il rejette uniquement pour les erreurs réseau.
// GET
const data = await (await fetch("/api/users")).json();

// POST avec body JSON
const res = await fetch("/api/users", {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({ nom: "Julien" })
});
if (!res.ok) throw new Error(res.statusText);
const user = await res.json();
Promise.all / Promise.allSettled Combinateurs de Promises Exécuter plusieurs opérations en parallèle
Promise.all : Lance toutes les promises en parallèle. Résout quand toutes sont résolues. Échoue si une seule échoue.

Promise.allSettled : Attend toutes les promises, retourne toutes les résolutions et rejections. Utile pour les cas où on veut tous les résultats.
// Parallel - plus rapide que séquentiel!
const [users, posts, stats] = await Promise.all([
  fetch("/api/users").then(r => r.json()),
  fetch("/api/posts").then(r => r.json()),
  fetch("/api/stats").then(r => r.json()),
]);

// allSettled : recupérer même les erreurs
const results = await Promise.allSettled([p1, p2, p3]);
results.forEach(r => {
  if (r.status === "fulfilled") use(r.value);
});

ES6+ JavaScript Moderne

Les fonctionnalités modernes de JavaScript indispensables en SaaS.

Destructuring Déstructuration Extraire des valeurs d'objets et tableaux
Rôle : Syntaxe ES6 pour extraire des valeurs d'objets ou de tableaux en variables. Peut inclure des valeurs par défaut et renommer.

Usage avancé : Très utilisé dans les paramètres de fonctions pour documenter les arguments attendus.
// Objet
const { nom, age, ville = "Paris" } = user;
// Renommer : const { nom: username } = user;

// Tableau
const [first, second, ...rest] = [1, 2, 3, 4];

// Dans les paramètres de fonction
function greet({ nom, role = "user" }) {
  return `${nom} (${role})`;
}
Spread ... / Rest ... Spread et Rest Étaler et collecter des éléments
Spread (...) : Étale un itérable dans un autre tableau/objet/appel de fonction. Crée des copies superficielles.

Rest (...) : Collecte les éléments restants dans un tableau (params de fonction) ou objet.

Distinction : Même syntaxe, direction opposée — spread étale, rest collecte.
// SPREAD — copier/fusionner
const arr2 = [...arr1, 4, 5];
const updated = { ...user, role: "admin" };
Math.max(...numbers);

// REST — collecter
function sum(...nums) {
  return nums.reduce((a, b) => a + b, 0);
}
const { id, ...rest } = user; // omit id
Map / Set Map et Set — Collections modernes Alternatives améliorées aux objets et tableaux
Map : Collection clé-valeur comme un objet, mais avec des clés de n'importe quel type, une taille accessible et un ordre préservé. Plus performant pour les ajouts/suppressions fréquents.

Set : Collection de valeurs uniques. Parfait pour dédupliquer des données.
// Map
const cache = new Map();
cache.set("user:1", { nom: "Julien" });
cache.get("user:1"); // { nom: "Julien" }
cache.has("user:1"); // true
cache.size; // 1

// Set — valeurs uniques
const tags = new Set(["js", "ts", "js"]);
// Set { "js", "ts" } — doublon supprimé

// Dédupliquer un tableau
const unique = [...new Set(arr)];
Optional Chaining ?. Chaînage optionnel Accès sécurisé aux propriétés profondes
Rôle : Permet d'accéder à des propriétés imbriquées sans déclencher une TypeError si une valeur intermédiaire est null ou undefined. Retourne undefined au lieu de planter.

Fonctionne aussi pour : méthodes (obj?.method()), tableaux (arr?.[0]), fonctions (fn?.()).
// Sans optional chaining — risque d'erreur
const city = user && user.address && user.address.city;

// Avec ?. — sûr et concis
const city = user?.address?.city;

// Méthode optionnelle
user?.getPermissions?.();

// Avec valeur par défaut (nullish)
const avatar = user?.profile?.avatar ?? "default.png";
import / export Modules ES6 Organiser le code en fichiers séparés
Export nommé : Exporte plusieurs éléments d'un module. Doit être importé avec le même nom.

Export par défaut : Un seul par fichier. Peut être importé avec n'importe quel nom.

import type : En TypeScript, importer uniquement des types (supprimé à la compilation).
// utils.js — exports nommés
export const PI = 3.14159;
export function formatDate(d) { ... }
export { helperA, helperB };

// UserService.js — export par défaut
export default class UserService { ... }

// Importer
import { PI, formatDate } from "./utils.js";
import UserService from "./UserService.js";
import * as Utils from "./utils.js";

Méthodes des Tableaux

Les méthodes fonctionnelles des arrays sont au cœur du développement JS moderne : transformer, filtrer et accûmuler des données.

.map()Transformer chaque élémentRetourne un nouveau tableau transformé
Rôle : Applique une fonction à chaque élément et retourne un nouveau tableau de même longueur. N'altère pas l'original.

Cas d'usage SaaS : Transformer des données API en composants UI, formater des prix, convertir des IDs en objets, générer du HTML dynamique.
const prices = [10, 25, 50]; const withTax = prices.map(p => p * 1.2); // [12, 30, 60] // Transformer des users en HTML const html = users.map(u => `<li class="user">${u.nom}</li>` ).join("");
.filter()Filtrer selon une conditionRetourne un sous-ensemble des éléments
Rôle : Retourne un nouveau tableau contenant uniquement les éléments pour lesquels la fonction retourne true. La longueur peut être inférieure.

Chaînage : .filter().map() est un pattern très courant : d'abord filtrer, ensuite transformer.
const users = [{actif: true}, {actif: false}]; const actifs = users .filter(u => u.actif) .map(u => u.nom); // Recherche const results = data .filter(item => item.nom.includes(query));
.reduce()Accûmuler en une valeurCalculer une somme, grouper, aplatir
Rôle : Réduit le tableau à une seule valeur en accûmulant un résultat. Le plus puissant mais aussi le plus complexe des méthodes de tableau.

Paramètres : reduce(callback, valeurInitiale). Le callback reçoit (accumulateur, valeurCourante).
// Somme const total = [10, 20, 30] .reduce((acc, n) => acc + n, 0); // 60 // Grouper par catégorie const grouped = items.reduce((acc, item) => { acc[item.cat] = [ ...(acc[item.cat] || []), item ]; return acc; }, {});
.find() / .some() / .every()Rechercher et testerTrouver un élément ou tester des conditions
.find() : Retourne le premier élément qui satisfait la condition, ou undefined. Très utile pour trouver un objet par ID.

.some() : Retourne true si au moins un élément satisfait la condition. Court-circuite dès le premier match.

.every() : Retourne true si tous les éléments satisfont la condition.
const user = users .find(u => u.id === 42); // { id: 42, nom: "Julien" } ou undefined const hasAdmin = users .some(u => u.role === "admin"); const allActif = users .every(u => u.actif);
.sort() / .slice() / .splice()Trier, extraire, modifierManipuler la structure du tableau
.sort() : Trie en place (modifie l'original!). Passer une fonction de comparaison pour un tri correct des nombres.

.slice(debut, fin) : Extrait sans modifier l'original. slice(-3) = les 3 derniers.

.splice(index, n, ...items) : Modifie l'original en supprimant/insérant des éléments.
// Tri numérique correct nums.sort((a, b) => a - b); // Tri alphabétique users.sort((a, b) => a.nom.localeCompare(b.nom)); // Pagination const page = items .slice((p-1)*10, p*10); // Supprimer par index arr.splice(index, 1);

Manipulation du DOM

Interagir avec les éléments HTML depuis JavaScript : sélection, événements, modification du contenu et des classes.

querySelectorSélectionner des élémentsAccéder aux éléments du DOM
Rôle : Sélectionne le premier élément correspondant au sélecteur CSS. querySelectorAll retourne tous les éléments sous forme de NodeList.

Syntaxe : Identique aux sélecteurs CSS : #id, .classe, tag, [attr], etc.
// Un seul élément const btn = document .querySelector("#submit-btn"); const nav = document .querySelector(".navbar"); // Tous les éléments const cards = document .querySelectorAll(".card"); // Convertir NodeList en Array const arr = [...cards];
addEventListenerEcouter les événementsClic, input, scroll, clavier...
Rôle : Attache une fonction à exécuter quand un événement se produit.

Evénements courants : click, input, change, submit, keydown, keyup, scroll, resize, DOMContentLoaded, mouseover, mouseout.

event.preventDefault() : Empêche le comportement par défaut (ex: soumission de formulaire).
btn.addEventListener("click", (e) => { console.log("Click!", e.target); }); form.addEventListener("submit", (e) => { e.preventDefault(); // stop rechargement console.log(e.target); }); input.addEventListener("input", (e) => { console.log(e.target.value); });
classListManipuler les classes CSSAjouter, supprimer, basculer des classes
Méthodes :
.add("classe") : ajouter
.remove("classe") : supprimer
.toggle("classe") : ajouter si absente, supprimer si présente
.contains("classe") : vérifier la présence (retourne booléen)
.replace("ancienne", "nouvelle") : remplacer
const menu = document .querySelector(".menu"); menu.classList.add("open"); menu.classList.remove("hidden"); menu.classList.toggle("active"); if (menu.classList.contains("open")) { menu.classList.replace("open", "closed"); }
innerHTML / textContentModifier le contenu d'un élémentInjecter du HTML ou du texte
innerHTML : Définit ou lit le HTML interne. Permet d'injecter des balises. Attention aux failles XSS si le contenu vient d'un utilisateur!

textContent : Définit le texte brut sans interpréter le HTML. Plus sécurisé pour le contenu utilisateur.

insertAdjacentHTML : Insère sans écraser le contenu existant.
const el = document .querySelector("#app"); // HTML (permet les balises) el.innerHTML = `<h1>Bonjour</h1>`; // Texte brut (sécurisé) el.textContent = userInput; // Ajouter sans écraser el.insertAdjacentHTML( "beforeend", "<li>Nouvel item</li>" );

🔒 Closures & Scope avancé

JS Avancé

Comprendre les closures, le lexical scope, le hoisting et le mot-clé this — fondamentaux pour écrire du JavaScript professionnel.

JS Closures Fonctions qui capturent leur environnement
Définition : Une closure est une fonction qui mémorise les variables de sa portée parente, même après que cette portée a été fermée. C'est le concept le plus important de JS.

Comment ça marche : Quand une fonction est créée, elle capture une référence vers son environnement lexical (les variables disponibles au moment de sa création).

Cas d'usage :
• Encapsulation de données (modules)
• Fonctions factory (créer des variantes)
• Callbacks et event handlers
• Mémoïsation / cache

Piège courant : Les closures capturent la référence à la variable, pas sa valeur au moment de la capture.
// Closure basique — compteur privé
function createCounter(initial = 0) {
  let count = initial; // Variable "enfermée"
  
  return {
    increment: () => ++count,
    decrement: () => --count,
    getValue: () => count,
    reset: () => { count = initial; }
  };
}

const counter = createCounter(10);
counter.increment(); // 11
counter.increment(); // 12
counter.getValue();  // 12
// count est inaccessible de l'extérieur ✅

// Factory function — créer des variantes
function createMultiplier(factor) {
  return (number) => number * factor;
}
const double = createMultiplier(2);
const triple = createMultiplier(3);
double(5);  // 10
triple(5);  // 15

// ⚠️ Piège classique avec var dans une boucle
for (var i = 0; i < 3; i++) {
  setTimeout(() => console.log(i), 100);
}
// Affiche : 3, 3, 3 (pas 0, 1, 2)

// ✅ Solution avec let (block scope)
for (let i = 0; i < 3; i++) {
  setTimeout(() => console.log(i), 100);
}
// Affiche : 0, 1, 2
JS Lexical Scope & Hoisting Portée statique et remontée des déclarations
Lexical Scope : La portée d'une variable est déterminée par où elle est écrite dans le code, pas où elle est appelée. JS recherche les variables de la portée la plus interne vers la plus externe (scope chain).

Hoisting : JS "remonte" les déclarations en haut de leur portée lors de la compilation :
var → déclaration remontée, valeur = undefined
let/const → remontées mais dans la Temporal Dead Zone (erreur si accédées avant déclaration)
function déclaration → entièrement remontée (corps inclus)
function expression → comme var/let

Portées : Globale → Fonction → Bloc (let/const)
// ─── Lexical Scope (scope chain) ───
const app = 'NovaDash';

function outer() {
  const version = '2.0';
  
  function inner() {
    const module = 'crypto';
    // Accès : module ✅, version ✅, app ✅
    console.log(`${app} v${version} — ${module}`);
  }
  
  inner();
  // Accès : version ✅, app ✅, module ❌
}

// ─── Hoisting — var vs let ───
console.log(a); // undefined (var est remonté)
console.log(b); // ❌ ReferenceError (TDZ)

var a = 1;
let b = 2;

// ─── Hoisting — fonctions ───
// Déclaration → entièrement remontée
greet(); // ✅ "Hello" — fonctionne !
function greet() { console.log('Hello'); }

// Expression → pas remontée
sayBye(); // ❌ TypeError
const sayBye = () => console.log('Bye');

// ─── Block scope ───
if (true) {
  var x = 1;   // Fuit hors du bloc
  let y = 2;   // Reste dans le bloc
  const z = 3; // Reste dans le bloc
}
console.log(x); // 1
console.log(y); // ❌ ReferenceError
JS this, call, apply, bind Le contexte d'exécution et comment le contrôler
this : Référence l'objet qui appelle la fonction. Sa valeur dépend du comment la fonction est appelée, pas où elle est écrite.

Règles de résolution :
1. new → this = nouvel objet
2. call/apply/bind → this = objet passé
3. Méthode d'objet → this = l'objet
4. Fonction libre → this = window (ou undefined en strict)
5. Arrow function → this = celui du scope parent (lexical)

call vs apply vs bind :
call(obj, arg1, arg2) → appel immédiat, args séparés
apply(obj, [args]) → appel immédiat, args en tableau
bind(obj) → retourne une nouvelle fonction (pas d'appel)
// ─── this selon le contexte ───
const user = {
  name: 'Julien',
  greet() {
    console.log(this.name); // 'Julien'
  },
  greetLater() {
    // ❌ this perdu dans setTimeout
    setTimeout(function() {
      console.log(this.name); // undefined
    }, 100);
    
    // ✅ Arrow function → this lexical
    setTimeout(() => {
      console.log(this.name); // 'Julien'
    }, 100);
  }
};

// ─── call / apply / bind ───
function introduce(greeting, emoji) {
  console.log(`${greeting} ${this.name} ${emoji}`);
}

const dev = { name: 'Julien' };

// call — args séparés
introduce.call(dev, 'Salut', '👋');

// apply — args en tableau
introduce.apply(dev, ['Salut', '👋']);

// bind — retourne une nouvelle fonction
const boundIntro = introduce.bind(dev);
boundIntro('Hello', '🚀'); // Hello Julien 🚀

// ─── Cas pratique : emprunt de méthode ───
const logger = {
  prefix: '[LOG]',
  log(msg) { console.log(`${this.prefix} ${msg}`); }
};

const errorLogger = { prefix: '[ERROR]' };
logger.log.call(errorLogger, 'Crash !');
// [ERROR] Crash !
JS IIFE & Module Pattern Encapsulation et état privé avant ES Modules
IIFE : Immediately Invoked Function Expression — une fonction qui s'exécute immédiatement. Crée une portée isolée pour éviter la pollution globale.

Module Pattern : Combine IIFE + closures pour créer des modules avec état privé et API publique. C'était LE pattern avant ES6 modules.

Revealing Module Pattern : Variante plus lisible qui déclare tout en privé puis "révèle" les méthodes publiques dans le return.

Aujourd'hui : Préférer les ES Modules (import/export), mais le module pattern reste utile pour comprendre les closures et encapsuler du code dans un seul fichier.
// ─── IIFE — Portée isolée ───
(function() {
  const secret = 'abc123';
  console.log('Initialisé');
  // secret n'existe pas dehors
})();

// Avec paramètres
(function(win, doc) {
  // Alias locaux pour window et document
})(window, document);

// ─── Module Pattern ───
const CryptoWallet = (function() {
  // 🔒 État privé
  let balance = 0;
  const transactions = [];
  
  // Fonction privée
  function log(type, amount) {
    transactions.push({ type, amount, date: new Date() });
  }
  
  // 🔓 API publique
  return {
    deposit(amount) {
      balance += amount;
      log('deposit', amount);
    },
    withdraw(amount) {
      if (amount > balance) throw new Error('Fonds insuffisants');
      balance -= amount;
      log('withdraw', amount);
    },
    getBalance: () => balance,
    getHistory: () => [...transactions] // copie
  };
})();

CryptoWallet.deposit(1000);
CryptoWallet.withdraw(250);
CryptoWallet.getBalance();   // 750
CryptoWallet.getHistory();   // [{...}, {...}]
// CryptoWallet.balance       // undefined 🔒
// CryptoWallet.transactions  // undefined 🔒

🧬 Prototypes & Classes avancées

JS Avancé

Le système d'héritage prototype de JavaScript et les classes ES6+ qui l'encapsulent. Comprendre les prototypes est essentiel pour maîtriser le langage.

JS Prototype Chain L'héritage natif de JavaScript
Prototype : Chaque objet JS possède un lien interne [[Prototype]] vers un autre objet. Quand on accède à une propriété absente, JS remonte la chaîne de prototypes jusqu'à null.

__proto__ vs prototype :
__proto__ → le prototype de l'instance (utiliser Object.getPrototypeOf())
.prototype → propriété des fonctions constructeurs, assignée aux instances créées avec new

Chaîne : instance → Constructor.prototype → Object.prototype → null

Performance : Les méthodes sur le prototype sont partagées entre toutes les instances (économie mémoire), contrairement aux méthodes définies dans le constructeur.
// ─── Constructeur + prototype ───
function Crypto(name, symbol) {
  this.name = name;     // Propre à chaque instance
  this.symbol = symbol;
}

// Méthode partagée via prototype
Crypto.prototype.display = function() {
  return `${this.name} (${this.symbol})`;
};

const btc = new Crypto('Bitcoin', 'BTC');
const eth = new Crypto('Ethereum', 'ETH');

btc.display(); // "Bitcoin (BTC)"
eth.display(); // "Ethereum (ETH)"

// Même fonction en mémoire
btc.display === eth.display; // true ✅

// ─── Chaîne de prototypes ───
console.log(
  Object.getPrototypeOf(btc) === Crypto.prototype, // true
  Object.getPrototypeOf(Crypto.prototype) === Object.prototype, // true
  Object.getPrototypeOf(Object.prototype) === null  // true — fin
);

// ─── Vérifications ───
btc instanceof Crypto;           // true
btc.hasOwnProperty('name');      // true (propre)
btc.hasOwnProperty('display');   // false (hérité)
'display' in btc;                // true (remonte la chaîne)

// ─── Object.create — héritage sans new ───
const baseConfig = { theme: 'dark', lang: 'fr' };
const userConfig = Object.create(baseConfig);
userConfig.fontSize = 16;
userConfig.theme;    // 'dark' (hérité)
userConfig.fontSize; // 16 (propre)
JS Classes ES6+ & Héritage Sucre syntaxique sur les prototypes
Rôle : Les classes ES6 sont du sucre syntaxique sur le système de prototypes. Même mécanique sous le capot, syntaxe plus claire.

Éléments :
constructor() → initialisation
• Méthodes → automatiquement sur le prototype
static → méthode de classe (pas d'instance)
get/set → propriétés calculées
extends → héritage
super() → appel du parent

Champs privés (ES2022) : Préfixe # pour les propriétés/méthodes vraiment privées (pas juste une convention).
class Portfolio {
  // Champ privé (ES2022)
  #holdings = new Map();
  #owner;

  constructor(owner) {
    this.#owner = owner;
  }

  // Méthode publique
  buy(symbol, amount) {
    const current = this.#holdings.get(symbol) || 0;
    this.#holdings.set(symbol, current + amount);
  }

  // Getter
  get totalAssets() {
    return this.#holdings.size;
  }

  // Méthode statique
  static compare(a, b) {
    return a.totalAssets - b.totalAssets;
  }

  // Méthode privée
  #validate(amount) {
    if (amount <= 0) throw new Error('Montant invalide');
  }
}

// ─── Héritage avec extends ───
class PremiumPortfolio extends Portfolio {
  #leverage;

  constructor(owner, leverage = 2) {
    super(owner); // Appel du constructeur parent
    this.#leverage = leverage;
  }

  // Override de méthode
  buy(symbol, amount) {
    super.buy(symbol, amount * this.#leverage);
  }
}

const p = new PremiumPortfolio('Julien', 3);
p.buy('BTC', 1);  // Achète 3 BTC (levier x3)
p.totalAssets;     // 1

// p.#holdings      // ❌ SyntaxError — privé
JS Symbol, Iterators & Generators Protocoles d'itération et valeurs uniques
Symbol : Type primitif qui crée des identifiants uniques et immuables. Utilisé comme clés de propriétés pour éviter les collisions et pour les protocoles internes (iterators, toString...).

Iterator Protocol : Un objet est itérable s'il implémente [Symbol.iterator]() qui retourne un objet avec une méthode next(). Permet l'utilisation de for...of, spread, destructuring.

Generators : Fonctions avec function* qui peuvent suspendre leur exécution avec yield. Retournent un iterator. Parfait pour les séquences paresseuses, la pagination, et les flux asynchrones.
// ─── Symbol ───
const id = Symbol('userId');
const user = { [id]: 42, name: 'Julien' };
user[id];        // 42
Object.keys(user); // ['name'] — Symbol non listé

// Symbols globaux partagés
const KEY = Symbol.for('app.key');
Symbol.for('app.key') === KEY; // true

// ─── Iterator personnalisé ───
class CryptoList {
  #coins;
  constructor(...coins) { this.#coins = coins; }

  [Symbol.iterator]() {
    let i = 0;
    const coins = this.#coins;
    return {
      next() {
        return i < coins.length
          ? { value: coins[i++], done: false }
          : { done: true };
      }
    };
  }
}

const list = new CryptoList('BTC', 'ETH', 'SOL');
for (const coin of list) console.log(coin);
const arr = [...list]; // ['BTC', 'ETH', 'SOL']

// ─── Generator ───
function* fibonacci() {
  let [a, b] = [0, 1];
  while (true) {
    yield a;
    [a, b] = [b, a + b];
  }
}

const fib = fibonacci();
fib.next().value; // 0
fib.next().value; // 1
fib.next().value; // 1
fib.next().value; // 2

// Generator pour pagination API
async function* fetchPages(url) {
  let page = 1;
  while (true) {
    const res = await fetch(`${url}?page=${page}`);
    const data = await res.json();
    if (data.length === 0) return;
    yield data;
    page++;
  }
}
JS Proxy & Reflect Intercepter et personnaliser les opérations sur les objets
Proxy : Crée un "piège" autour d'un objet pour intercepter les opérations (lecture, écriture, suppression, appel de fonction...). C'est la base de la réactivité dans Vue.js 3.

Traps courants :
get(target, prop) → lecture de propriété
set(target, prop, value) → écriture
has(target, prop) → opérateur in
deleteProperty(target, prop)delete
apply(target, thisArg, args) → appel de fonction

Reflect : API miroir qui fournit les comportements par défaut des traps. Utilisé dans les handlers pour déléguer au comportement original.
// ─── Proxy — Validation automatique ───
function createValidated(schema) {
  return new Proxy({}, {
    set(target, prop, value) {
      if (schema[prop]) {
        const { type, min, max } = schema[prop];
        if (typeof value !== type)
          throw new TypeError(`${prop} doit être ${type}`);
        if (min !== undefined && value < min)
          throw new RangeError(`${prop} min: ${min}`);
        if (max !== undefined && value > max)
          throw new RangeError(`${prop} max: ${max}`);
      }
      return Reflect.set(target, prop, value);
    },
    get(target, prop) {
      if (!(prop in target))
        console.warn(`Propriété "${prop}" non définie`);
      return Reflect.get(target, prop);
    }
  });
}

const trade = createValidated({
  amount: { type: 'number', min: 0 },
  symbol: { type: 'string' },
  leverage: { type: 'number', min: 1, max: 100 }
});

trade.symbol = 'BTC';     // ✅
trade.amount = 1000;       // ✅
trade.leverage = 50;       // ✅
// trade.amount = -5;      // ❌ RangeError
// trade.symbol = 123;     // ❌ TypeError

// ─── Proxy — Observable (style Vue.js) ───
function reactive(obj, onChange) {
  return new Proxy(obj, {
    set(target, prop, value) {
      const old = target[prop];
      const result = Reflect.set(target, prop, value);
      if (old !== value) onChange(prop, value, old);
      return result;
    }
  });
}

const state = reactive({ count: 0 }, (prop, val) => {
  console.log(`${prop} changed to ${val}`);
});
state.count = 5; // "count changed to 5"

🔄 Event Loop & Concurrence

JS Avancé

Comment JavaScript gère l'asynchrone avec un seul thread. Comprendre l'event loop, les microtasks et macrotasks, et les patterns de concurrence avancés.

JS Event Loop en détail Call stack, microtasks, macrotasks
JavaScript est single-threaded — un seul fil d'exécution. L'event loop permet le multitâche non-bloquant en déléguant les opérations lentes (I/O, timers, réseau) aux APIs du navigateur.

Ordre d'exécution :
1. Call Stack — code synchrone en cours
2. Microtask Queue — Promises (.then), queueMicrotask, MutationObserver
3. Macrotask Queue — setTimeout, setInterval, I/O, events DOM

Règle clé : Les microtasks sont TOUJOURS exécutées avant les macrotasks. Après chaque macrotask, TOUTES les microtasks en attente sont vidées.

requestAnimationFrame : Exécuté avant le prochain repaint du navigateur (~60fps). Idéal pour les animations.
// ─── Quiz : quel ordre d'affichage ? ───
console.log('1 — Sync');

setTimeout(() => console.log('2 — Timeout'), 0);

Promise.resolve().then(() => console.log('3 — Promise'));

queueMicrotask(() => console.log('4 — Microtask'));

console.log('5 — Sync');

// Résultat :
// 1 — Sync        (call stack)
// 5 — Sync        (call stack)
// 3 — Promise     (microtask)
// 4 — Microtask   (microtask)
// 2 — Timeout     (macrotask)

// ─── Pourquoi c'est important ───
// Les microtasks peuvent bloquer le rendu !
Promise.resolve().then(function loop() {
  // ⚠️ Boucle infinie de microtasks
  // Le navigateur ne peut JAMAIS peindre
  Promise.resolve().then(loop);
});

// ─── requestAnimationFrame ───
function animate(element) {
  let start = null;
  
  function step(timestamp) {
    if (!start) start = timestamp;
    const progress = (timestamp - start) / 1000;
    
    element.style.transform = 
      `translateX(${progress * 200}px)`;
    
    if (progress < 2) {
      requestAnimationFrame(step); // ~60fps
    }
  }
  
  requestAnimationFrame(step);
}
JS Promises avancées all, allSettled, race, any et chaînage
Combinateurs de Promises :
Promise.all([...]) → attend TOUTES. Échoue si UNE échoue
Promise.allSettled([...]) → attend TOUTES, jamais d'échec. Retourne le statut de chaque promise
Promise.race([...]) → retourne la PREMIÈRE (résolue OU rejetée)
Promise.any([...]) → retourne la PREMIÈRE résolue. Échoue seulement si TOUTES échouent

Cas d'usage SaaS :
all → charger plusieurs API en parallèle
allSettled → dashboard multi-sources (certaines peuvent échouer)
race → timeout sur une requête
any → fallback entre plusieurs serveurs
// ─── Promise.all — tout ou rien ───
const [user, trades, prices] = await Promise.all([
  fetch('/api/user').then(r => r.json()),
  fetch('/api/trades').then(r => r.json()),
  fetch('/api/prices').then(r => r.json())
]);
// Si UNE échoue → tout échoue

// ─── Promise.allSettled — résultats partiels ───
const results = await Promise.allSettled([
  fetch('/api/binance'),
  fetch('/api/kraken'),
  fetch('/api/coinbase')
]);

results.forEach(r => {
  if (r.status === 'fulfilled') 
    console.log('OK:', r.value);
  else 
    console.log('Erreur:', r.reason);
});

// ─── Promise.race — timeout pattern ───
function fetchWithTimeout(url, ms = 5000) {
  return Promise.race([
    fetch(url),
    new Promise((_, reject) =>
      setTimeout(() => reject(new Error('Timeout')), ms)
    )
  ]);
}

// ─── Promise.any — premier succès ───
const fastest = await Promise.any([
  fetch('https://api1.example.com/price'),
  fetch('https://api2.example.com/price'),
  fetch('https://api3.example.com/price')
]);
// Retourne la première réponse réussie

// ─── Chaînage avancé ───
const portfolio = await fetch('/api/portfolio')
  .then(r => { if (!r.ok) throw r; return r.json(); })
  .then(data => data.filter(c => c.value > 100))
  .then(filtered => filtered.sort((a, b) => b.value - a.value))
  .catch(err => { console.error(err); return []; })
  .finally(() => console.log('Requête terminée'));
JS Web Workers Calculs lourds sans bloquer l'UI
Problème : JS est single-threaded — un calcul lourd (analyse de données, ML, crypto) bloque l'interface utilisateur.

Web Workers : Exécutent du JS dans un thread séparé. Communication par messages (postMessage / onmessage). Pas d'accès au DOM.

Types :
Dedicated Worker — un seul script propriétaire
Shared Worker — partagé entre plusieurs onglets
Service Worker — proxy réseau (cache, offline, push notifications)

Transferables : Pour les gros tableaux, utilisez postMessage(data, [buffer]) pour transférer la mémoire (pas copier) — beaucoup plus rapide.
// ─── Main thread (app.js) ───
const worker = new Worker('analyzer.js');

// Envoyer des données au worker
worker.postMessage({
  type: 'ANALYZE',
  prices: [95000, 95200, 94800, 95500, 96000]
});

// Recevoir les résultats
worker.onmessage = (event) => {
  const { sma, rsi, signal } = event.data;
  document.getElementById('signal').textContent = signal;
};

worker.onerror = (err) => console.error('Worker:', err);

// Terminer le worker
// worker.terminate();

// ─── Worker (analyzer.js) ───
self.onmessage = function(event) {
  const { type, prices } = event.data;
  
  if (type === 'ANALYZE') {
    // Calculs lourds sans bloquer l'UI
    const sma = prices.reduce((a, b) => a + b) 
                / prices.length;
    const rsi = calculateRSI(prices);
    const signal = rsi > 70 ? 'SELL' : 
                   rsi < 30 ? 'BUY' : 'HOLD';
    
    // Retourner les résultats
    self.postMessage({ sma, rsi, signal });
  }
};

function calculateRSI(prices) {
  // ... calcul intensif du RSI
  return 65;
}

// ─── Inline Worker (sans fichier séparé) ───
const blob = new Blob([`
  self.onmessage = (e) => {
    const result = e.data * 2;
    self.postMessage(result);
  };
`], { type: 'application/javascript' });

const inlineWorker = new Worker(URL.createObjectURL(blob));
JS AbortController & Patterns async Annuler des requêtes, debounce, retry
AbortController : Permet d'annuler des requêtes fetch, des streams, ou toute opération asynchrone. Essentiel pour les recherches en temps réel, les changements de page et les composants démontés.

Debounce : Attend que l'utilisateur arrête de taper pendant X ms avant d'exécuter. Idéal pour les recherches.

Throttle : Exécute au maximum une fois toutes les X ms. Idéal pour le scroll, le resize.

Retry avec backoff : Relance une requête échouée avec un délai croissant (exponentiel). Standard pour les API instables.
// ─── AbortController — annuler des requêtes ───
let controller = null;

async function searchCrypto(query) {
  // Annuler la requête précédente
  if (controller) controller.abort();
  controller = new AbortController();
  
  try {
    const res = await fetch(`/api/search?q=${query}`, {
      signal: controller.signal
    });
    return await res.json();
  } catch (err) {
    if (err.name === 'AbortError') return; // Ignoré
    throw err;
  }
}

// ─── Debounce ───
function debounce(fn, delay = 300) {
  let timer;
  return (...args) => {
    clearTimeout(timer);
    timer = setTimeout(() => fn(...args), delay);
  };
}

const debouncedSearch = debounce(searchCrypto, 400);
input.addEventListener('input', e => {
  debouncedSearch(e.target.value);
});

// ─── Throttle ───
function throttle(fn, limit = 100) {
  let waiting = false;
  return (...args) => {
    if (waiting) return;
    fn(...args);
    waiting = true;
    setTimeout(() => { waiting = false; }, limit);
  };
}

// ─── Retry avec exponential backoff ───
async function fetchWithRetry(url, retries = 3) {
  for (let i = 0; i < retries; i++) {
    try {
      const res = await fetch(url);
      if (res.ok) return await res.json();
      throw new Error(`HTTP ${res.status}`);
    } catch (err) {
      if (i === retries - 1) throw err;
      const delay = Math.pow(2, i) * 1000; // 1s, 2s, 4s
      await new Promise(r => setTimeout(r, delay));
    }
  }
}

🏗️ Design Patterns

JS Avancé

Patterns architecturaux essentiels pour structurer des applications JavaScript maintenables et scalables.

JS Singleton & Factory Créer des instances contrôlées
Singleton : Garantit qu'une classe n'a qu'une seule instance. Utile pour les connexions DB, les configs globales, les stores. En JS moderne, un simple module ES6 est déjà un singleton (mis en cache après le premier import).

Factory : Crée des objets sans exposer la logique de création. Le code appelant ne sait pas quelle classe concrète est instanciée — il demande un type et reçoit l'objet.

Quand utiliser :
• Singleton → config, logger, connexion API, cache
• Factory → création d'éléments UI, parsers, notifications
// ─── Singleton avec classe ───
class ApiClient {
  static #instance = null;
  #baseUrl;
  #token;

  constructor(baseUrl) {
    if (ApiClient.#instance) return ApiClient.#instance;
    this.#baseUrl = baseUrl;
    this.#token = null;
    ApiClient.#instance = this;
  }

  setToken(token) { this.#token = token; }

  async get(path) {
    return fetch(`${this.#baseUrl}${path}`, {
      headers: { Authorization: `Bearer ${this.#token}` }
    }).then(r => r.json());
  }
}

const api1 = new ApiClient('https://api.novadash.fr');
const api2 = new ApiClient('https://other.url');
api1 === api2; // true — même instance

// ─── Singleton avec module ES6 (plus simple) ───
// api-client.js
// export default new ApiClient('https://...');
// → Même instance partout grâce au cache du module

// ─── Factory Pattern ───
class Notification {
  static create(type, message) {
    switch (type) {
      case 'success': return new SuccessNotif(message);
      case 'error':   return new ErrorNotif(message);
      case 'warning': return new WarningNotif(message);
      default: throw new Error(`Type inconnu: ${type}`);
    }
  }
}

class SuccessNotif {
  constructor(msg) { this.msg = msg; this.color = '#0f0'; }
  show() { /* ... */ }
}
class ErrorNotif {
  constructor(msg) { this.msg = msg; this.color = '#f00'; }
  show() { /* ... */ }
}

const n = Notification.create('success', 'Trade exécuté');
n.show();
JS Observer & Pub/Sub Communication événementielle entre modules
Observer : Un objet (le sujet) maintient une liste d'observateurs et les notifie automatiquement en cas de changement d'état. Base de la réactivité dans les frameworks.

Pub/Sub (EventEmitter) : Version découplée — les publishers émettent des événements sur un bus central, les subscribers écoutent les événements qui les intéressent. Aucune connaissance directe entre émetteur et récepteur.

Cas d'usage :
• Observer → binding UI, formulaires réactifs
• Pub/Sub → communication entre modules indépendants, microservices frontend, logging centralisé
// ─── Observer Pattern ───
class Observable {
  #observers = new Set();

  subscribe(fn) {
    this.#observers.add(fn);
    return () => this.#observers.delete(fn); // unsubscribe
  }

  notify(data) {
    this.#observers.forEach(fn => fn(data));
  }
}

// Utilisation
const priceStream = new Observable();

const unsub = priceStream.subscribe(price => {
  document.getElementById('btc').textContent = price;
});

priceStream.subscribe(price => {
  if (price > 100000) alert('BTC > 100K !');
});

priceStream.notify(95000); // Tous les observers notifiés
unsub(); // Désabonner le premier observer

// ─── EventEmitter (Pub/Sub) ───
class EventBus {
  #events = new Map();

  on(event, handler) {
    if (!this.#events.has(event))
      this.#events.set(event, new Set());
    this.#events.get(event).add(handler);
    return () => this.#events.get(event).delete(handler);
  }

  emit(event, ...args) {
    this.#events.get(event)?.forEach(fn => fn(...args));
  }

  once(event, handler) {
    const unsub = this.on(event, (...args) => {
      handler(...args);
      unsub();
    });
  }
}

// Bus global de l'app
const bus = new EventBus();

// Module A — émet
bus.emit('trade:executed', { symbol: 'BTC', amount: 0.5 });

// Module B — écoute (ne connaît pas A)
bus.on('trade:executed', (trade) => {
  console.log(`Trade: ${trade.symbol}`);
});
JS Strategy & Command Comportements interchangeables et actions réversibles
Strategy : Encapsule des algorithmes interchangeables. Le contexte délègue le travail à la stratégie active. Élimine les gros blocs if/else ou switch.

Command : Encapsule une action en objet, permettant de la stocker, passer en paramètre, annuler (undo), ou rejouer (redo).

En JS idiomatique : Ces patterns se simplifient souvent en objets littéraux + fonctions de premier ordre (pas besoin de classes complexes comme en Java).
// ─── Strategy — Algorithmes interchangeables ───
const sortStrategies = {
  price:  (a, b) => b.price - a.price,
  name:   (a, b) => a.name.localeCompare(b.name),
  volume: (a, b) => b.volume - a.volume,
  change: (a, b) => b.change24h - a.change24h
};

function sortCryptos(cryptos, strategy = 'price') {
  return [...cryptos].sort(sortStrategies[strategy]);
}

const coins = [
  { name: 'Bitcoin', price: 95000, volume: 50e9, change24h: 2.1 },
  { name: 'Ethereum', price: 3200, volume: 20e9, change24h: -1.3 },
];

sortCryptos(coins, 'price');   // Par prix
sortCryptos(coins, 'name');    // Alphabétique
sortCryptos(coins, 'change');  // Par variation

// ─── Command — Undo/Redo ───
class CommandManager {
  #history = [];
  #position = -1;

  execute(command) {
    // Supprimer le futur si on a fait undo
    this.#history.splice(this.#position + 1);
    command.execute();
    this.#history.push(command);
    this.#position++;
  }

  undo() {
    if (this.#position < 0) return;
    this.#history[this.#position].undo();
    this.#position--;
  }

  redo() {
    if (this.#position >= this.#history.length - 1) return;
    this.#position++;
    this.#history[this.#position].execute();
  }
}

// Commande concrète
const addTrade = (portfolio, trade) => ({
  execute: () => portfolio.push(trade),
  undo: () => portfolio.pop()
});

const mgr = new CommandManager();
const portfolio = [];
mgr.execute(addTrade(portfolio, { symbol: 'BTC' }));
mgr.execute(addTrade(portfolio, { symbol: 'ETH' }));
mgr.undo();  // Retire ETH
mgr.redo();  // Remet ETH
JS Memoization & Currying Optimisation fonctionnelle et composition
Memoization : Cache le résultat d'une fonction pour les mêmes arguments. Évite les recalculs coûteux. Fonctionne uniquement avec les fonctions pures (même entrée → même sortie).

Currying : Transforme une fonction de N arguments en N fonctions d'un argument. Permet la partial application — pré-remplir certains paramètres pour créer des variantes spécialisées.

Composition : Combiner des fonctions simples pour construire des transformations complexes. pipe(f, g, h)(x) = h(g(f(x))).
// ─── Memoization ───
function memoize(fn) {
  const cache = new Map();
  return (...args) => {
    const key = JSON.stringify(args);
    if (cache.has(key)) return cache.get(key);
    const result = fn(...args);
    cache.set(key, result);
    return result;
  };
}

const expensiveCalc = memoize((prices) => {
  console.log('Calcul RSI...');
  return prices.reduce((a, b) => a + b) / prices.length;
});

expensiveCalc([95, 96, 94]); // "Calcul RSI..." → 95
expensiveCalc([95, 96, 94]); // Cache hit — pas de recalcul

// ─── Currying ───
const curry = (fn) => {
  const arity = fn.length;
  return function curried(...args) {
    if (args.length >= arity) return fn(...args);
    return (...more) => curried(...args, ...more);
  };
};

const formatPrice = curry((currency, decimals, amount) => 
  `${amount.toFixed(decimals)} ${currency}`
);

// Créer des variantes spécialisées
const formatUSD = formatPrice('$', 2);
const formatBTC = formatPrice('BTC', 8);

formatUSD(95000);     // "95000.00 $"
formatBTC(0.00045);   // "0.00045000 BTC"

// ─── Composition (pipe) ───
const pipe = (...fns) => (x) => 
  fns.reduce((acc, fn) => fn(acc), x);

const processPrice = pipe(
  (p) => p * 1.2,           // Ajouter 20% de marge
  (p) => Math.round(p),     // Arrondir
  (p) => formatUSD(p)       // Formater
);

processPrice(100); // "120.00 $"
JS Error Handling avancé Erreurs custom, boundaries, logging global
Erreurs personnalisées : Créez des classes d'erreurs spécifiques qui étendent Error. Permet de différencier les types d'erreurs dans les catch et de transporter des données contextuelles (code HTTP, champ invalide...).

Gestion globale :
window.onerror → erreurs non capturées
window.onunhandledrejection → Promises non capturées
try/catch → erreurs synchrones et async/await

Pattern Result : Au lieu de throw, retourner { ok, data, error }. Inspiré de Rust/Go — rend la gestion d'erreur explicite sans exceptions.
// ─── Erreurs personnalisées ───
class AppError extends Error {
  constructor(message, code, details = {}) {
    super(message);
    this.name = 'AppError';
    this.code = code;
    this.details = details;
    this.timestamp = new Date().toISOString();
  }
}

class ValidationError extends AppError {
  constructor(field, message) {
    super(message, 'VALIDATION_ERROR', { field });
    this.name = 'ValidationError';
  }
}

class ApiError extends AppError {
  constructor(status, message) {
    super(message, 'API_ERROR', { status });
    this.name = 'ApiError';
  }
}

// Utilisation
async function createTrade(data) {
  if (!data.symbol) 
    throw new ValidationError('symbol', 'Symbole requis');
  
  const res = await fetch('/api/trade', { method: 'POST' });
  if (!res.ok) 
    throw new ApiError(res.status, 'Trade échoué');
  
  return res.json();
}

try {
  await createTrade({});
} catch (err) {
  if (err instanceof ValidationError) {
    showFieldError(err.details.field, err.message);
  } else if (err instanceof ApiError) {
    showToast(`Erreur serveur (${err.details.status})`);
  } else {
    throw err; // Erreur inattendue → remonter
  }
}

// ─── Pattern Result (sans exceptions) ───
async function safeFetch(url) {
  try {
    const res = await fetch(url);
    const data = await res.json();
    return { ok: true, data };
  } catch (error) {
    return { ok: false, error };
  }
}

const result = await safeFetch('/api/price/BTC');
if (result.ok) console.log(result.data);
else console.error(result.error);

// ─── Gestion globale ───
window.addEventListener('unhandledrejection', (e) => {
  console.error('Promise non gérée:', e.reason);
  // Envoyer au service de monitoring
});

🌐 Web APIs avancées

JS Avancé

APIs navigateur puissantes pour le stockage, les communications temps réel, les notifications et l'observation du DOM.

JS Storage: localStorage, sessionStorage, IndexedDB Persister des données côté client
localStorage : Stockage clé/valeur persistant (survit à la fermeture du navigateur). ~5-10 Mo par domaine. Synchrone.

sessionStorage : Idem mais effacé à la fermeture de l'onglet. Utile pour les données temporaires de session.

IndexedDB : Base de données objet côté client. Asynchrone, transactionnelle, supporte les index et les requêtes. Pas de limite de taille pratique. Pour les apps offline, le cache de données volumineuses.

Cookies vs Storage : Les cookies sont envoyés à chaque requête HTTP (overhead réseau). localStorage/sessionStorage ne sont jamais envoyés au serveur.
// ─── localStorage ───
// Stocker (toujours en string)
localStorage.setItem('theme', 'dark');
localStorage.setItem('user', JSON.stringify({
  name: 'Julien', plan: 'premium'
}));

// Lire
const theme = localStorage.getItem('theme');
const user = JSON.parse(localStorage.getItem('user'));

// Supprimer
localStorage.removeItem('theme');
localStorage.clear(); // Tout supprimer

// Écouter les changements (entre onglets !)
window.addEventListener('storage', (e) => {
  console.log(`${e.key}: ${e.oldValue} → ${e.newValue}`);
});

// ─── Wrapper typé avec expiration ───
const store = {
  set(key, value, ttlMinutes = null) {
    const item = { value, created: Date.now() };
    if (ttlMinutes) item.expires = Date.now() + ttlMinutes * 60000;
    localStorage.setItem(key, JSON.stringify(item));
  },
  get(key) {
    const raw = localStorage.getItem(key);
    if (!raw) return null;
    const item = JSON.parse(raw);
    if (item.expires && Date.now() > item.expires) {
      localStorage.removeItem(key);
      return null; // Expiré
    }
    return item.value;
  }
};

store.set('prices', { BTC: 95000 }, 5); // Expire dans 5min
store.get('prices'); // { BTC: 95000 } ou null

// ─── IndexedDB (simplifié) ───
async function openDB(name, version = 1) {
  return new Promise((resolve, reject) => {
    const req = indexedDB.open(name, version);
    req.onupgradeneeded = (e) => {
      const db = e.target.result;
      db.createObjectStore('trades', { keyPath: 'id' });
    };
    req.onsuccess = () => resolve(req.result);
    req.onerror = () => reject(req.error);
  });
}

const db = await openDB('NovaDash');
const tx = db.transaction('trades', 'readwrite');
tx.objectStore('trades').add({ id: 1, symbol: 'BTC' });
JS WebSocket & Server-Sent Events Communication temps réel bidirectionnelle
WebSocket : Connexion bidirectionnelle persistante entre client et serveur. Pas de polling — les données arrivent instantanément. Idéal pour le trading live, les chats, les jeux.

Server-Sent Events (SSE) : Flux unidirectionnel du serveur vers le client. Plus simple que WebSocket, reconnexion automatique, fonctionne avec HTTP standard. Idéal pour les notifications, les feeds en direct.

Quand choisir :
WebSocket → bidirectionnel (chat, trading, jeu)
SSE → serveur → client uniquement (notifications, prix live)
Polling → fallback si WS/SSE impossibles
// ─── WebSocket ───
class CryptoSocket {
  #ws; #url; #reconnectDelay = 1000;

  constructor(url) { this.#url = url; this.connect(); }

  connect() {
    this.#ws = new WebSocket(this.#url);
    
    this.#ws.onopen = () => {
      console.log('Connecté');
      this.#ws.send(JSON.stringify({
        action: 'subscribe',
        channels: ['BTC-USD', 'ETH-USD']
      }));
    };

    this.#ws.onmessage = (event) => {
      const data = JSON.parse(event.data);
      this.updateUI(data);
    };

    this.#ws.onclose = () => {
      console.log('Déconnecté — reconnexion...');
      setTimeout(() => this.connect(), this.#reconnectDelay);
      this.#reconnectDelay = Math.min(
        this.#reconnectDelay * 2, 30000
      );
    };
  }

  send(data) {
    if (this.#ws.readyState === WebSocket.OPEN) {
      this.#ws.send(JSON.stringify(data));
    }
  }

  updateUI(data) {
    document.querySelector(`#${data.symbol}`)
      .textContent = data.price;
  }
}

const ws = new CryptoSocket('wss://stream.exchange.com');

// ─── Server-Sent Events ───
const source = new EventSource('/api/stream/prices');

source.onmessage = (event) => {
  const price = JSON.parse(event.data);
  console.log(`${price.symbol}: ${price.value}`);
};

// Événements nommés
source.addEventListener('alert', (e) => {
  const alert = JSON.parse(e.data);
  showNotification(alert.message);
});

source.onerror = () => console.log('SSE reconnexion...');
// source.close(); // Fermer
JS Observers : Intersection, Resize, Mutation Observer le DOM de manière performante
IntersectionObserver : Détecte quand un élément entre/sort du viewport. Utilisé pour le lazy loading, les animations au scroll, le tracking de visibilité, le infinite scroll.

ResizeObserver : Détecte les changements de taille d'un élément. Plus précis que window.resize — observe un élément spécifique, pas toute la fenêtre.

MutationObserver : Observe les changements du DOM (ajout/suppression d'éléments, attributs, texte). Utile pour les composants tiers, les extensions, le monitoring de changements dynamiques.

Avantage : Tous les observers sont asynchrones et performants — ils ne bloquent pas le thread principal contrairement aux événements scroll/resize classiques.
// ─── IntersectionObserver — Lazy loading ───
const lazyObserver = new IntersectionObserver(
  (entries) => {
    entries.forEach(entry => {
      if (entry.isIntersecting) {
        const img = entry.target;
        img.src = img.dataset.src;
        img.classList.add('loaded');
        lazyObserver.unobserve(img); // Stop
      }
    });
  },
  { rootMargin: '200px' } // Précharger 200px avant
);

document.querySelectorAll('img[data-src]')
  .forEach(img => lazyObserver.observe(img));

// ─── Animate on scroll ───
const animObserver = new IntersectionObserver(
  (entries) => {
    entries.forEach(entry => {
      entry.target.classList.toggle(
        'visible', entry.isIntersecting
      );
    });
  },
  { threshold: 0.2 } // 20% visible
);

document.querySelectorAll('.el-card')
  .forEach(el => animObserver.observe(el));

// ─── ResizeObserver ───
const resizer = new ResizeObserver((entries) => {
  for (const entry of entries) {
    const { width } = entry.contentRect;
    entry.target.classList.toggle('compact', width < 400);
  }
});
resizer.observe(document.querySelector('.dashboard'));

// ─── MutationObserver ───
const mutObserver = new MutationObserver((mutations) => {
  mutations.forEach(m => {
    if (m.type === 'childList') {
      console.log('Nœuds ajoutés:', m.addedNodes.length);
    }
  });
});
mutObserver.observe(document.body, {
  childList: true, subtree: true
});
JS Clipboard, Notifications & Fullscreen APIs système du navigateur
Clipboard API : Lire et écrire dans le presse-papiers. Requiert HTTPS. writeText() pour copier, readText() pour coller (demande permission).

Notifications API : Affiche des notifications système (même quand l'onglet est inactif). Requiert la permission de l'utilisateur. Combinée avec les Service Workers pour les push notifications.

Fullscreen API : Passe un élément en plein écran. Utile pour les dashboards, les graphiques, les jeux et les présentations.

Vibration API : Fait vibrer l'appareil mobile. Utile pour les alertes de prix.
// ─── Clipboard API ───
// Copier du texte
async function copyToClipboard(text) {
  try {
    await navigator.clipboard.writeText(text);
    showToast('Copié !');
  } catch (err) {
    // Fallback pour HTTP
    const ta = document.createElement('textarea');
    ta.value = text;
    document.body.appendChild(ta);
    ta.select();
    document.execCommand('copy');
    ta.remove();
  }
}

// Bouton "copier l'adresse wallet"
copyBtn.onclick = () => copyToClipboard('0xABC...DEF');

// ─── Notifications API ───
async function sendNotification(title, body) {
  if (Notification.permission === 'default') {
    await Notification.requestPermission();
  }
  if (Notification.permission === 'granted') {
    new Notification(title, {
      body,
      icon: '/img/logo.png',
      badge: '/img/badge.png',
      tag: 'price-alert', // Remplace la précédente
      requireInteraction: true
    });
  }
}

sendNotification('BTC Alert', 'Bitcoin > 100K $ !');

// ─── Fullscreen API ───
const chart = document.getElementById('chart');

function toggleFullscreen(element) {
  if (!document.fullscreenElement) {
    element.requestFullscreen();
  } else {
    document.exitFullscreen();
  }
}

document.addEventListener('fullscreenchange', () => {
  chart.classList.toggle('fullscreen', 
    !!document.fullscreenElement);
});

// ─── Vibration (mobile) ───
navigator.vibrate?.(200); // Vibrer 200ms
navigator.vibrate?.([100, 50, 100]); // Pattern
JS Drag & Drop API Glisser-déposer natif HTML5
Drag & Drop : API native HTML5 pour le glisser-déposer. Pas besoin de librairie pour les cas simples.

Événements source (élément glissé) :
dragstart → début du drag
drag → pendant le mouvement
dragend → fin (drop ou annulation)

Événements cible (zone de dépôt) :
dragenter → entre dans la zone
dragover → au-dessus (preventDefault obligatoire !)
dragleave → sort de la zone
drop → élément relâché

DataTransfer : Objet qui transporte les données entre la source et la cible. Supporte du texte, du HTML, des fichiers.
// ─── Drag & Drop — Liste réordonneable ───

// Rendre les éléments draggables
document.querySelectorAll('.trade-item').forEach(item => {
  item.draggable = true;
  
  item.addEventListener('dragstart', (e) => {
    e.dataTransfer.setData('text/plain', item.id);
    item.classList.add('dragging');
    e.dataTransfer.effectAllowed = 'move';
  });
  
  item.addEventListener('dragend', () => {
    item.classList.remove('dragging');
  });
});

// Zone de dépôt
const dropzone = document.querySelector('.portfolio');

dropzone.addEventListener('dragover', (e) => {
  e.preventDefault(); // OBLIGATOIRE pour autoriser le drop
  e.dataTransfer.dropEffect = 'move';
  
  // Trouver l'élément le plus proche pour insérer
  const afterEl = getDragAfterElement(dropzone, e.clientY);
  const dragging = document.querySelector('.dragging');
  if (afterEl) {
    dropzone.insertBefore(dragging, afterEl);
  } else {
    dropzone.appendChild(dragging);
  }
});

dropzone.addEventListener('drop', (e) => {
  e.preventDefault();
  const id = e.dataTransfer.getData('text/plain');
  console.log(`Déposé : ${id}`);
});

function getDragAfterElement(container, y) {
  const elements = [...container.querySelectorAll(
    '.trade-item:not(.dragging)')
  ];
  return elements.reduce((closest, child) => {
    const box = child.getBoundingClientRect();
    const offset = y - box.top - box.height / 2;
    if (offset < 0 && offset > closest.offset) {
      return { offset, element: child };
    }
    return closest;
  }, { offset: Number.NEGATIVE_INFINITY }).element;
}

Performance & Sécurité

JS Avancé

Optimisations de performance, bonnes pratiques de sécurité et outils de mesure pour des applications JavaScript de qualité production.

JS Performance & Optimisation Lazy loading, virtual scroll, Web Vitals
Performance API : Mesurer précisément les temps d'exécution avec performance.now(), performance.mark() et performance.measure().

Lazy Loading : Charger les ressources à la demande. Images avec loading="lazy", modules avec import() dynamique, composants au scroll.

DOM Batching : Minimiser les accès au DOM. Regrouper les lectures puis les écritures. Utiliser DocumentFragment pour les insertions multiples.

Web Vitals :
LCP (Largest Contentful Paint) < 2.5s
FID (First Input Delay) < 100ms
CLS (Cumulative Layout Shift) < 0.1
// ─── Performance API ───
performance.mark('start-fetch');
const data = await fetch('/api/data').then(r => r.json());
performance.mark('end-fetch');
performance.measure('API Call', 'start-fetch', 'end-fetch');

const [measure] = performance.getEntriesByName('API Call');
console.log(`API: ${measure.duration.toFixed(2)}ms`);

// ─── Import dynamique (code splitting) ───
button.onclick = async () => {
  const { ChartModule } = await import('./chart.js');
  ChartModule.render(data);
};

// ─── DOM Batching avec DocumentFragment ───
function renderList(items) {
  const fragment = document.createDocumentFragment();
  
  items.forEach(item => {
    const li = document.createElement('li');
    li.textContent = `${item.name}: ${item.price}$`;
    fragment.appendChild(li);
  });
  
  // UN SEUL accès DOM au lieu de N
  document.getElementById('list').appendChild(fragment);
}

// ─── Virtual Scroll (principe) ───
function virtualScroll(container, items, itemHeight) {
  const visibleCount = Math.ceil(
    container.clientHeight / itemHeight
  ) + 2; // Buffer
  
  container.onscroll = () => {
    const scrollTop = container.scrollTop;
    const startIdx = Math.floor(scrollTop / itemHeight);
    const visibleItems = items.slice(
      startIdx, startIdx + visibleCount
    );
    
    renderList(visibleItems);
    // Spacer pour le scroll
    container.style.paddingTop = 
      `${startIdx * itemHeight}px`;
  };
}

// ─── requestIdleCallback ───
requestIdleCallback((deadline) => {
  while (deadline.timeRemaining() > 0) {
    // Tâches non urgentes (analytics, préchargement)
    doBackgroundWork();
  }
});
JS Sécurité JavaScript XSS, CSRF, sanitization, CSP
XSS (Cross-Site Scripting) : Injection de code malveillant via des données utilisateur. Règle d'or : ne JAMAIS utiliser innerHTML avec des données non fiables. Utiliser textContent ou sanitizer.

CSRF : Requête forgée par un site tiers. Protection : tokens CSRF, cookie SameSite, vérification Origin/Referer.

Content Security Policy (CSP) : En-tête HTTP qui restreint les sources de scripts, styles, images. Bloque les injections même si XSS réussit.

Bonnes pratiques :
textContent au lieu de innerHTML
• Valider côté client ET serveur
• HttpOnly + Secure sur les cookies sensibles
• CORS restrictif
// ─── XSS — Le problème ───
const userInput = '<img onerror="alert(1)" src=x>';

// ❌ DANGEREUX — exécute le script
element.innerHTML = userInput;

// ✅ SAFE — échappe automatiquement
element.textContent = userInput;

// ─── Sanitization manuelle ───
function sanitizeHTML(str) {
  const div = document.createElement('div');
  div.textContent = str;
  return div.innerHTML;
  // <script> → &lt;script&gt;
}

// ─── Sanitizer API (moderne) ───
// const sanitizer = new Sanitizer();
// element.setHTML(userInput, { sanitizer });

// ─── Échapper pour les URL ───
const query = encodeURIComponent(userInput);
const url = `/search?q=${query}`;
// Empêche l'injection dans l'URL

// ─── Protection CSRF ───
async function secureFetch(url, options = {}) {
  const csrfToken = document.querySelector(
    'meta[name="csrf-token"]'
  )?.content;
  
  return fetch(url, {
    ...options,
    headers: {
      ...options.headers,
      'X-CSRF-Token': csrfToken,
      'Content-Type': 'application/json'
    },
    credentials: 'same-origin' // Cookies same-origin
  });
}

// ─── Validation d'entrée ───
function validateEmail(email) {
  const re = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
  if (!re.test(email)) throw new Error('Email invalide');
  if (email.length > 254) throw new Error('Email trop long');
  return email.toLowerCase().trim();
}

// ─── Stockage sécurisé ───
// ❌ Ne JAMAIS stocker en localStorage :
// - Tokens JWT sensibles
// - Mots de passe
// - Données personnelles en clair
// → Utiliser des cookies HttpOnly + Secure
JS WeakMap, WeakRef & Gestion mémoire Références faibles et garbage collection
Garbage Collector (GC) : JS libère automatiquement la mémoire des objets sans référence. Mais les closures, les event listeners oubliés et les caches peuvent créer des memory leaks.

WeakMap : Map dont les clés sont des références faibles. Si l'objet clé n'a plus d'autre référence, il peut être GC. Pas énumérable, pas de .size. Idéal pour associer des métadonnées à des objets DOM.

WeakSet : Comme Set mais avec des références faibles. Utile pour marquer des objets (visité, traité...).

WeakRef (ES2021) : Référence faible vers un objet. .deref() retourne l'objet ou undefined s'il a été GC. Utile pour les caches intelligents.
// ─── WeakMap — métadonnées sans memory leak ───
const metadata = new WeakMap();

function trackElement(element) {
  metadata.set(element, {
    clickCount: 0,
    createdAt: Date.now()
  });
  
  element.addEventListener('click', () => {
    const data = metadata.get(element);
    data.clickCount++;
  });
}

// Si l'élément est supprimé du DOM,
// les métadonnées sont automatiquement GC ✅

// ─── WeakMap — données privées de classe ───
const _private = new WeakMap();

class Wallet {
  constructor(balance) {
    _private.set(this, { balance, pin: null });
  }
  
  get balance() { return _private.get(this).balance; }
  
  setPin(pin) { _private.get(this).pin = pin; }
}

const w = new Wallet(1000);
w.balance;       // 1000
_private.get(w); // { balance: 1000, pin: null }
// Inaccessible sans la référence _private

// ─── WeakRef — Cache intelligent ───
class SmartCache {
  #cache = new Map();

  set(key, value) {
    this.#cache.set(key, new WeakRef(value));
  }

  get(key) {
    const ref = this.#cache.get(key);
    if (!ref) return undefined;
    
    const obj = ref.deref();
    if (!obj) {
      this.#cache.delete(key); // GC a nettoyé
      return undefined;
    }
    return obj;
  }
}

// ─── Éviter les memory leaks ───
// ❌ Event listener jamais supprimé
// element.addEventListener('click', handler);

// ✅ Nettoyer à la destruction
const controller = new AbortController();
element.addEventListener('click', handler, {
  signal: controller.signal
});
// Plus tard : controller.abort(); // Supprime le listener
JS structuredClone, JSON avancé & Intl Clonage profond, sérialisation et internationalisation
structuredClone() : Clone profond natif d'objets (ES2022). Gère les objets imbriqués, Map, Set, Date, RegExp, ArrayBuffer. Remplace JSON.parse(JSON.stringify()) qui ne gère ni les dates, ni les undefined, ni les références circulaires.

JSON avancé : JSON.stringify accepte un replacer (filtre) et un spacer. JSON.parse accepte un reviver pour transformer les valeurs à la lecture.

Intl (Internationalisation) : API native pour formater les nombres, monnaies, dates, listes et messages selon la locale. Plus besoin de librairies pour le formatage basique.
// ─── structuredClone ───
const original = {
  user: { name: 'Julien' },
  trades: [{ symbol: 'BTC', date: new Date() }],
  meta: new Map([['version', 2]])
};

// Clone profond — indépendant de l'original
const clone = structuredClone(original);
clone.user.name = 'Alice';
original.user.name; // 'Julien' — non affecté ✅
clone.trades[0].date instanceof Date; // true ✅

// ─── JSON avancé ───
// Replacer — filtrer/transformer
const json = JSON.stringify(original, (key, value) => {
  if (key === 'pin') return undefined; // Exclure
  if (value instanceof Date) return value.toISOString();
  return value;
}, 2); // 2 = indentation

// Reviver — transformer à la lecture
const parsed = JSON.parse(json, (key, value) => {
  // Reconvertir les dates ISO en objets Date
  if (typeof value === 'string' && 
      /\d{4}-\d{2}-\d{2}T/.test(value)) {
    return new Date(value);
  }
  return value;
});

// ─── Intl — Formatage localisé ───
// Monnaie
new Intl.NumberFormat('fr-FR', {
  style: 'currency', currency: 'EUR'
}).format(95000); // "95 000,00 €"

new Intl.NumberFormat('en-US', {
  style: 'currency', currency: 'USD',
  notation: 'compact'
}).format(95000); // "$95K"

// Date
new Intl.DateTimeFormat('fr-FR', {
  dateStyle: 'full', timeStyle: 'short'
}).format(new Date()); // "vendredi 28 février 2026 à 14:30"

// Relatif
new Intl.RelativeTimeFormat('fr', { numeric: 'auto' })
  .format(-1, 'day'); // "hier"

// Liste
new Intl.ListFormat('fr', { type: 'conjunction' })
  .format(['BTC', 'ETH', 'SOL']); // "BTC, ETH et SOL"

Introduction à TypeScript

TypeScript est un surensemble typé de JavaScript. Il compile vers du JavaScript standard.

TS vs JSPourquoi TypeScript ?Avantages du typage statique
TypeScript = JavaScript + Types. Tout code JS valide est aussi du code TS valide.

Avantages :
• Détection des bugs avant l'exécution
• Autocomplétion IDE et documentation intégrée
• Refactoring sécurisé sur de gros projets
• Standard industrie SaaS (Angular, Next.js, Nest.js)
// JavaScript — bug silencieux function add(a, b) { return a + b; } add("5", 3); // "53" bug! // TypeScript — erreur à la compilation function add(a: number, b: number): number { return a + b; } add("5", 3); // Erreur TS!
: typeAnnotation de typevariable : Type — la syntaxe fondamentale
Syntaxe : Ajouter : Type après le nom d'une variable, paramètre ou propriété.

Inférence : TypeScript peut souvent deviner le type automatiquement. Annotez surtout les paramètres de fonctions — les variables locales initiálisées n'en ont souvent pas besoin.
// Annotation explicite let nom: string = "Julien"; let age: number = 28; let actif: boolean = true; // Inférence (pas besoin d'annoter) let ville = "Paris"; // TS infère: string let score = 100; // TS infère: number

Interfaces TypeScript

Les interfaces définissent la forme des objets. Elles sont le pilier de la structuration de données en TypeScript.

interfaceDéclaration d'interfaceDéfinit le contrat d'un objet
Rôle : Définit un contrat que les objets doivent respecter — toutes les propriétés requises avec les bons types.

Interface vs type : interface pour les objets (extensible avec extends, declaration merging). type pour les unions, intersections et types complexes.
interface User { id: number; nom: string; email: string; avatar?: string; // optionnel readonly createdAt: Date; } const user: User = { id: 1, nom: "Julien", email: "j@jlqdev.fr", createdAt: new Date() };
extendsHéritage d'interfacesComposer des interfaces par héritage
Rôle : extends permet à une interface d'hériter des propriétés d'une ou plusieurs autres interfaces.

Héritage multiple : Contrairement aux classes, une interface peut étendre plusieurs interfaces simultanément.
interface BaseEntity { id: number; createdAt: Date; } interface User extends BaseEntity { nom: string; email: string; } // Héritage multiple interface Admin extends User, Permissions { superAdmin: boolean; }

Types Avancés

Union, literal types, keyof, typeof et discriminated unions.

Union | Type Union La valeur peut être l'un OU l'autre type
Rôle : Définit qu'une valeur peut être de l'un ou l'autre type. Le type le plus utilisé en TypeScript après les types de base.

Narrowing : TypeScript rétrécit automatiquement le type dans les branches conditionnelles après une vérification.
type ID = string | number;
type Status = "active" | "pending" | "deleted";

function processId(id: string | number) {
  if (typeof id === "string") {
    id.toUpperCase(); // ✅ string ici
  } else {
    id.toFixed(2); // ✅ number ici
  }
}
Literal Types Types littéraux Valeurs exactes comme types
Rôle : Restreindre un type à des valeurs exactes. Plus précis que string ou number — TypeScript vérifie que seules ces valeurs sont utilisées.

Combiné avec union : Créer des types d'état finis, très utiles pour les SaaS.
// Type littéral simple
type Direction = "up" | "down" | "left" | "right";

// Type d'état SaaS
type OrderStatus =
  | "cart"
  | "checkout"
  | "paid"
  | "shipped"
  | "delivered";

function move(dir: Direction) { }
move("up"); // ✅
move("jump"); // ❌ Erreur TS
keyof / typeof keyof et typeof Extraire les types de clés et de variables
keyof : Produit un union type de toutes les clés d'un type objet. Permet des accès sûrs aux propriétés.

typeof : Extrait le type TypeScript d'une valeur ou variable. Utile pour typer à partir de valeurs existantes sans redéfinir.
// keyof
interface User { nom: string; age: number; }
type UserKey = keyof User; // "nom" | "age"

function getField<T, K extends keyof T>(obj: T, key: K): T[K] {
  return obj[key];
}

// typeof
const config = { port: 3000, host: "localhost" };
type Config = typeof config;
// { port: number; host: string; }
Discriminated Union Union discriminante Union avec discriminant pour différencier les types
Rôle : Pattern où chaque membre de l'union a une propriété commune (le discriminant) avec une valeur littérale unique. TypeScript peut rétrécir le type automatiquement selon cette propriété.

C'est le pattern de base pour les state machines TypeScript.
type AsyncState<T> =
  | { status: "idle" }
  | { status: "loading" }
  | { status: "success"; data: T }
  | { status: "error"; error: string };

function render(state: AsyncState<User>) {
  switch (state.status) {
    case "success": return state.data; // ✅ data typée
    case "error": return state.error; // ✅ error typée
  }
}

Generics

Les Generics permettent de créer des composants réutilisables tout en conservant la sécurité du typage.

<T>Fonction génériqueFonctions qui acceptent n'importe quel type
Rôle : <T> est un paramètre de type — un placeholder remplacé par le type réel à l'utilisation.

Avantage vs any : Contrairement à any, les generics conservent la relation entre les types. TypeScript peut vérifier l'utilisation des données.
// Sans generic — perd le type function first(arr: any[]): any { ... } // Avec generic — conserve le type! function first<T>(arr: T[]): T { return arr[0]; } first([1, 2, 3]); // type: number first(["a", "b"]); // type: string
ApiResponse<T>Interface génériqueTypes réutilisables pour les API
Rôle : Les interfaces et classes peuvent être génériques — on les paramètre avec un type à l'utilisation.

Pattern SaaS : Un type ApiResponse<T> générique réutilisé pour toutes les réponses API garantit la cohérence.
interface ApiResponse<T> { data: T; status: number; message: string; } type UserRes = ApiResponse<User>; type ListRes = ApiResponse<User[]>; class Store<T> { items: T[] = []; add(item: T) { this.items.push(item); } }

Utility Types

Types utilitaires intégrés pour transformer les types existants.

Partial<T> Partial — Tout optionnel Rend toutes les propriétés optionnelles
Rôle : Crée un type où toutes les propriétés de T deviennent optionnelles. Indispensable pour les fonctions de mise à jour partielle (PATCH).

Implémentation interne : { [P in keyof T]?: T[P] }
interface User {
  nom: string;
  email: string;
  role: string;
}

// Mise à jour partielle
function updateUser(id: string, data: Partial<User>) {
  // data peut avoir 0, 1 ou 3 propriétés
}

updateUser("1", { email: "new@mail.com" }); // ✅
Pick<T, K> / Omit<T, K> Pick et Omit — Sélection de propriétés Sélectionner ou exclure des propriétés d'un type
Pick<T, K> : Sélectionne uniquement les propriétés listées dans K. Crée un sous-type.

Omit<T, K> : Exclut les propriétés listées dans K. L'inverse de Pick. Très utilisé pour créer des DTOs.
interface User {
  id: number; nom: string; email: string;
  password: string; createdAt: Date;
}

// Aperçu public
type UserCard = Pick<User, "id" | "nom">;

// Création (sans id et createdAt auto)
type CreateUserDTO = Omit<User, "id" | "createdAt">;

// DTO public (sans mot de passe)
type PublicUser = Omit<User, "password">;
Record<K, V> Record — Type dictionnaire Crée un type objet avec clés et valeurs typées
Rôle : Crée un type objet dont les clés sont de type K et les valeurs de type V. Alternative typée aux { [key: string]: value }.

Particulièrement utile : Pour des maps, caches, tables de correspondance.
// Dictionnaire
type Scores = Record<string, number>;
const scores: Scores = { alice: 95, bob: 87 };

// Clés typées (union)
type Status = "active" | "pending" | "deleted";
type StatusConfig = Record<Status, { label: string; color: string }>;

const config: StatusConfig = {
  active: { label: "Actif", color: "green" },
  pending: { label: "En attente", color: "yellow" },
  deleted: { label: "Supprimé", color: "red" },
};
ReturnType / Parameters ReturnType et Parameters Extraire les types d'une fonction
ReturnType<T> : Extrait le type de retour d'une fonction. Utile pour typer à partir d'une implémentation existante.

Parameters<T> : Extrait les types des paramètres en tuple.

Awaited<T> : Extrait le type résolu d'une Promise.
async function fetchUser(id: string) {
  return { id, nom: "Julien", role: "admin" };
}

// Extraire le type de retour
type FetchResult = ReturnType<typeof fetchUser>;
// Promise<{ id: string; nom: string; role: string }>

// Résoudre la Promise
type User = Awaited<FetchResult>;
// { id: string; nom: string; role: string }

⚛️ React — Fondamentaux

Frameworks JS

Bibliothèque UI de Meta pour construire des interfaces déclaratives par composants. Approche fonctionnelle avec hooks. Écosystème : Next.js, React Router, Redux/Zustand, React Query.

React Composant & JSX Fonctions qui retournent du HTML enrichi
Rôle : Un composant React est une fonction JavaScript qui retourne du JSX — une syntaxe hybride HTML/JS. Chaque composant est réutilisable et reçoit des données via les props.

Règles JSX :
• Retourner un seul élément racine (ou <Fragment> / <>...</>)
className au lieu de class
htmlFor au lieu de for
• Les expressions JS sont entre {accolades}

Convention : Nom en PascalCase. Un fichier par composant.
// Composant fonctionnel avec props
function UserCard({ name, role, avatar }) {
  return (
    <div className="card">
      <img src={avatar} alt={name} />
      <h3>{name}</h3>
      <span className="badge">{role}</span>
    </div>
  );
}

// Utilisation


// Fragment (pas de div wrapper)
function Stats() {
return (
<>

Statistiques

Total : 42

); }
React useState État local réactif du composant
Rôle : Crée une variable d'état réactive. Quand l'état change via le setter, React re-rend le composant automatiquement.

Syntaxe : const [valeur, setValeur] = useState(initial)

Règles importantes :
• Ne jamais modifier l'état directement (count++ ❌)
• Toujours utiliser le setter (setCount(count + 1) ✅)
• Pour les objets/tableaux : toujours créer une copie
• Callback pour état basé sur le précédent : setCount(prev => prev + 1)
import { useState } from 'react';

function Counter() {
const [count, setCount] = useState(0);
const [user, setUser] = useState({
name: ‘Julien’, score: 0
});

return (

Compteur : {count}

``` {/* Mise à jour d'objet (spread) */} <button onClick={() => setUser(prev => ({ ...prev, score: prev.score + 10 }))}> +10 points </button> </div> ``` ); }
React useEffect Effets de bord : API, timers, subscriptions
Rôle : Exécute du code après le rendu du composant. Utilisé pour les appels API, les abonnements, les timers, et toute opération qui n'est pas du rendu pur.

Tableau de dépendances :
[] vide = exécuté une seule fois (montage)
[var1, var2] = exécuté quand var1 ou var2 changent
• Absent = exécuté à chaque rendu (rarement voulu)

Cleanup : La fonction retournée est appelée au démontage (ou avant la ré-exécution).
import { useState, useEffect } from 'react';

function CryptoPrice({ symbol }) {
const [price, setPrice] = useState(null);
const [loading, setLoading] = useState(true);

// Appel API au montage + quand symbol change
useEffect(() => {
setLoading(true);
fetch(`/api/crypto/${symbol}`)
.then(res => res.json())
.then(data => {
setPrice(data.price);
setLoading(false);
});
}, [symbol]); // ← dépendance

// Timer avec cleanup
useEffect(() => {
const id = setInterval(() => {
console.log(‘refresh…’);
}, 5000);
return () => clearInterval(id); // cleanup
}, []);

if (loading) return 

Chargement…

; return

{symbol} : {price} $

; }
React Rendu conditionnel & Listes Afficher dynamiquement selon l'état
Conditions : Pas de if dans le JSX — on utilise l'opérateur ternaire ? : ou le && pour afficher conditionnellement.

Listes : Utilisez .map() pour transformer un tableau en éléments JSX. Chaque élément doit avoir une key unique et stable (jamais l'index sauf pour des listes statiques).

Pourquoi key : React utilise les clés pour identifier quel élément a changé, été ajouté ou supprimé — c'est essentiel pour la performance du Virtual DOM.
function Dashboard({ user, transactions }) {
  return (
    <div>
      {/* Condition ternaire */}
      {user ? (
        <h2>Bonjour {user.name}</h2>
      ) : (
        <h2>Connectez-vous</h2>
      )}

```
  {/* Affichage conditionnel (&&) */}
  {user?.isAdmin && (
    <button>Panel Admin</button>
  )}

  {/* Liste avec map + key */}
  <ul>
    {transactions.map(tx => (
      <li key={tx.id}>
        {tx.label} — {tx.amount} €
      </li>
    ))}
  </ul>

  {/* Liste vide */}
  {transactions.length === 0 && (
    <p>Aucune transaction</p>
  )}
</div>
```

);
}
React useRef & Custom Hooks Références DOM et logique réutilisable
useRef : Crée une référence persistante qui ne déclenche pas de re-rendu. Deux usages : accéder à un élément DOM, ou stocker une valeur mutable (timer ID, valeur précédente).

Custom Hooks : Fonctions préfixées par use qui encapsulent de la logique réutilisable. Elles peuvent utiliser tous les hooks React à l'intérieur.

Convention : useFetch, useLocalStorage, useDebounce...
import { useRef, useState, useEffect } from 'react';

// useRef — accès DOM
function SearchBar() {
const inputRef = useRef(null);

useEffect(() => {
inputRef.current.focus(); // auto-focus
}, []);

return ;
}

// Custom Hook — logique réutilisable
function useFetch(url) {
const [data, setData] = useState(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);

useEffect(() => {
fetch(url)
.then(res => res.json())
.then(setData)
.catch(setError)
.finally(() => setLoading(false));
}, [url]);

return { data, loading, error };
}

// Utilisation du hook
function CryptoList() {
const { data, loading } = useFetch(’/api/cryptos’);
if (loading) return 

Chargement…

; return data.map(c =>

{c.name}

); }
React React Router & Context API Navigation SPA et état global
React Router : Navigation côté client sans rechargement de page. Transforme l'app en SPA (Single Page Application). <Link> remplace <a> pour la navigation interne.

Context API : Partage d'état global sans passer les props à travers chaque niveau de composants (prop drilling). Idéal pour les thèmes, l'authentification, la langue.

Quand utiliser Context vs Redux/Zustand : Context pour les données peu changeantes (thème, user). Redux/Zustand pour les données fréquemment mises à jour.
// ─── React Router ───
import { BrowserRouter, Routes, Route, Link } 
  from 'react-router-dom';

function App() {
return (



} />
} />
} />
} />


);
}

// ─── Context API ───
import { createContext, useContext, useState } from ‘react’;

const ThemeContext = createContext();

function ThemeProvider({ children }) {
const [dark, setDark] = useState(true);
return (

{children}

);
}

// Dans n’importe quel composant enfant
function Header() {
const { dark, setDark } = useContext(ThemeContext);
return ;
}

💚 Vue.js — Fondamentaux

Frameworks JS

Framework progressif créé par Evan You. Syntaxe template intuitive, réactivité automatique et courbe d'apprentissage douce. Écosystème : Nuxt, Vue Router, Pinia, Vite.

Vue Composant SFC & Template Single File Component avec <script setup>
SFC (Single File Component) : Un fichier .vue contient le template HTML, le script JS et le style CSS — tout est co-localisé.

<script setup> : Syntaxe Composition API simplifiée (Vue 3.2+). Tout ce qui est déclaré dans le script est automatiquement disponible dans le template. Plus besoin de return.

Props : Déclarées avec defineProps(). Les données parentales descendent vers les enfants via les props (flux unidirectionnel).
<!-- UserCard.vue -->
<script setup>
// Props typées
const props = defineProps({
  name: { type: String, required: true },
  role: { type: String, default: 'Dev' },
  avatar: String
});
</script>






Vue ref() & reactive() État réactif automatique
ref() : Rend une valeur primitive réactive. Accès via .value dans le script, mais pas dans le template (auto-unwrap).

reactive() : Rend un objet ou tableau profondément réactif. Pas besoin de .value. Ne pas réassigner l'objet entier.

Quand utiliser quoi :
ref() pour les primitifs (string, number, boolean)
reactive() pour les objets complexes
• En pratique, ref() pour tout fonctionne très bien
<script setup>
import { ref, reactive, computed } from 'vue';

// ref — valeurs primitives
const count = ref(0);
const name = ref(‘Julien’);

// reactive — objets
const user = reactive({
name: ‘Julien’,
score: 0,
portfolio: [‘BTC’, ‘ETH’]
});

// computed — valeur calculée (mise en cache)
const doubled = computed(() => count.value * 2);

// Méthodes
function increment() {
count.value++;          // .value dans le script
user.score += 10;       // pas de .value
}


Vue Directives v-if / v-for / v-model Rendu conditionnel, listes et binding formulaire
v-if / v-else-if / v-else : Rendu conditionnel — l'élément est retiré du DOM si faux. v-show masque avec CSS (meilleur pour les toggles fréquents).

v-for : Boucle sur un tableau ou objet. Toujours ajouter :key unique.

v-model : Binding bidirectionnel pour les formulaires — l'input modifie l'état ET l'état modifie l'input automatiquement.

v-bind (:) : Lie dynamiquement un attribut. Raccourci :src="url"
v-on (@) : Écoute un événement. Raccourci @click="fn"
<script setup>
import { ref } from 'vue';

const search = ref(’’);
const cryptos = ref([
{ id: 1, name: ‘Bitcoin’, price: 95000 },
{ id: 2, name: ‘Ethereum’, price: 3200 },
{ id: 3, name: ‘Solana’, price: 180 }
]);
const isLoggedIn = ref(true);


Vue watch() & Cycle de vie Observer les changements et hooks de montage
watch() : Observe un ou plusieurs ref/reactive et exécute du code quand la valeur change. Idéal pour les appels API en réponse à un changement.

watchEffect() : Exécuté immédiatement et re-exécuté quand ses dépendances changent (auto-détection). Plus simple que watch() quand on veut juste "réagir".

Hooks de cycle de vie :
onMounted() — DOM prêt (équiv. componentDidMount)
onUnmounted() — nettoyage (timers, subscriptions)
onUpdated() — après chaque mise à jour du DOM
<script setup>
import { ref, watch, watchEffect, 
         onMounted, onUnmounted } from 'vue';

const symbol = ref(‘BTC’);
const price = ref(null);

// watch — observer un changement
watch(symbol, async (newVal, oldVal) => {
console.log(`${oldVal} → ${newVal}`);
const res = await fetch(`/api/price/${newVal}`);
price.value = await res.json();
});

// watchEffect — auto-détection
watchEffect(() => {
document.title = `${symbol.value} : ${price.value}`;
});

// Lifecycle hooks
onMounted(() => {
console.log(‘Composant monté, DOM prêt’);
// Initialiser un timer, chart, WebSocket…
});

let intervalId;
onMounted(() => {
intervalId = setInterval(() => {
// Refresh des prix
}, 5000);
});

onUnmounted(() => {
clearInterval(intervalId); // Nettoyage
});
Vue Vue Router & Pinia Navigation SPA et store global
Vue Router : Routeur officiel de Vue. Navigation SPA avec <RouterLink> et <RouterView>. Supporte les paramètres dynamiques, les gardes de navigation et le lazy loading.

Pinia : Store officiel de Vue (remplace Vuex). Plus simple, typé, et compatible avec les DevTools Vue.

Structure Pinia :
state → données (comme ref/reactive)
getters → données calculées (comme computed)
actions → méthodes (modifications de l'état)
// ─── Vue Router ───
// router/index.js
import { createRouter, createWebHistory } from 'vue-router';

const router = createRouter({
history: createWebHistory(),
routes: [
{ path: ‘/’, component: () => import(’./Home.vue’) },
{ path: ‘/crypto/:id’, component: () =>
import(’./CryptoDetail.vue’) },
{ path: ‘/:pathMatch(.*)’, component: NotFound }
]
});

// Dans un composant
import { useRoute, useRouter } from ‘vue-router’;
const route = useRoute();     // route.params.id
const router = useRouter();   // router.push(’/home’)

// ─── Pinia Store ───
// stores/crypto.js
import { defineStore } from ‘pinia’;

export const useCryptoStore = defineStore(‘crypto’, {
state: () => ({
coins: [],
loading: false
}),
getters: {
topCoins: (state) =>
state.coins.slice(0, 10)
},
actions: {
async fetchCoins() {
this.loading = true;
const res = await fetch(’/api/coins’);
this.coins = await res.json();
this.loading = false;
}
}
});

// Utilisation dans un composant
const store = useCryptoStore();
store.fetchCoins();

🅰️ Angular — Fondamentaux

Frameworks JS

Framework complet de Google basé sur TypeScript. Architecture orientée composants avec dependency injection, services et RxJS. Écosystème : Angular CLI, Angular Material, NgRx, Signals.

Angular Composant & Décorateurs Classes TypeScript décorées avec @Component
Rôle : Un composant Angular est une classe TypeScript décorée par @Component qui lie un template HTML, une feuille de style et une logique.

Structure : Contrairement à React/Vue, Angular utilise des fichiers séparés par défaut (template, style, logique, tests) — mais le mode inline est possible.

@Input() : Reçoit des données du parent (comme les props React/Vue).
@Output() : Émet des événements vers le parent.

Standalone (Angular 14+) : standalone: true supprime le besoin de NgModules — plus simple et proche de React/Vue.
// user-card.component.ts
import { Component, Input, Output, EventEmitter } 
  from '@angular/core';

@Component({
selector: ‘app-user-card’,
standalone: true,
template: `<div class="card"> <img [src]="avatar" [alt]="name" /> <h3>{{ name }}</h3> <span class="badge">{{ role }}</span> <button (click)="onSelect.emit(name)"> Sélectionner </button> </div>`,
styles: [`.card {  background: rgba(255,255,255,0.05); border-radius: 12px; padding: 16px;  }`]
})
export class UserCardComponent {
@Input() name = ‘’;
@Input() role = ‘Dev’;
@Input() avatar = ‘’;
@Output() onSelect = new EventEmitter();
}

// Utilisation dans un template parent
// 
Angular Signals & État réactif Réactivité moderne Angular 16+
Signals (Angular 16+) : Nouveau système de réactivité granulaire. Un signal est un wrapper autour d'une valeur qui notifie les consommateurs quand elle change.

signal() : Crée un signal modifiable. Lecture avec (), écriture avec .set(), .update(), .mutate().

computed() : Signal dérivé, recalculé automatiquement quand ses dépendances changent (comme computed en Vue).

effect() : Exécute du code quand un signal change (comme useEffect en React ou watchEffect en Vue).

Avantage : Remplace le change detection de Zone.js — plus performant et plus prévisible.
import { Component, signal, computed, effect } 
  from '@angular/core';

@Component({
selector: ‘app-counter’,
standalone: true,
template: `<p>Compteur : {{ count() }}</p> <p>Double : {{ doubled() }}</p> <button (click)="increment()">+1</button> <button (click)="reset()">Reset</button>`
})
export class CounterComponent {
// Signal — état réactif
count = signal(0);

// Computed — dérivé automatique
doubled = computed(() => this.count() * 2);

// Modification
increment() {
this.count.update(c => c + 1);
}

reset() {
this.count.set(0);
}

constructor() {
// Effect — réaction aux changements
effect(() => {
console.log(`Count changed: ${this.count()}`);
});
}
}
Angular Template Syntax & Directives @if, @for, binding et pipes
Nouvelle syntaxe (Angular 17+) : @if, @for, @switch remplacent les directives structurelles *ngIf, *ngFor. Plus lisible et performant.

Binding :
[propriété]="expr" → property binding (parent → enfant)
(event)="handler()" → event binding
[(ngModel)]="var" → two-way binding (formulaires)
{{ expr }} → interpolation texte

Pipes : Transforment les données dans le template : | date, | currency, | uppercase, | async. On peut créer des pipes personnalisés.
// dashboard.component.ts
@Component({
  selector: 'app-dashboard',
  standalone: true,
  imports: [FormsModule, CurrencyPipe, DatePipe],
  template: `
    <!-- Two-way binding formulaire -->
    <input [(ngModel)]="search" placeholder="Filtrer" />

```
<!-- Nouvelle syntaxe @if (Angular 17+) -->
@if (isLoggedIn()) {
  <h2>Bienvenue {{ userName() }}</h2>
} @else {
  <p>Connectez-vous</p>
}

<!-- @for avec track obligatoire -->
@for (crypto of cryptos(); track crypto.id) {
  <div class="crypto-row">
    <span>{{ crypto.name }}</span>
    <!-- Pipe currency -->
    <span>{{ crypto.price | currency:'USD' }}</span>
    <!-- Property + Event binding -->
    <button 
      [disabled]="crypto.price === 0"
      (click)="selectCrypto(crypto)">
      Détails
    </button>
  </div>
} @empty {
  <p>Aucune crypto trouvée</p>
}

<!-- Pipe date -->
<p>Mis à jour : {{ lastUpdate | date:'short' }}</p>
```

`
})
Angular Services & Dependency Injection Logique métier partagée et injection automatique
Services : Classes qui encapsulent la logique métier, les appels API et l'état partagé. Décorés par @Injectable. Séparent la logique de l'affichage.

Dependency Injection (DI) : Angular crée et injecte automatiquement les instances de services dans les composants via le constructeur ou inject().

providedIn: 'root' : Le service est un singleton global — une seule instance pour toute l'application. C'est le pattern le plus courant.

HttpClient : Service intégré pour les requêtes HTTP. Retourne des Observables RxJS (comme des Promises mais annulables et composables).
// services/crypto.service.ts
import { Injectable, inject } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { signal } from '@angular/core';

@Injectable({ providedIn: ‘root’ })
export class CryptoService {
private http = inject(HttpClient);

// État partagé via signals
coins = signal([]);
loading = signal(false);

fetchCoins() {
this.loading.set(true);
this.http.get(’/api/coins’)
.subscribe({
next: (data) => {
this.coins.set(data);
this.loading.set(false);
},
error: (err) => {
console.error(err);
this.loading.set(false);
}
});
}
}

// Utilisation dans un composant
@Component({ … })
export class CryptoListComponent {
// inject() — méthode moderne (Angular 14+)
private cryptoService = inject(CryptoService);

coins = this.cryptoService.coins;
loading = this.cryptoService.loading;

ngOnInit() {
this.cryptoService.fetchCoins();
}
}
Angular Routing & Navigation Routes, guards, lazy loading
Angular Router : Routeur intégré puissant avec navigation SPA, paramètres dynamiques, gardes et lazy loading.

Lazy Loading : Charge les modules/composants à la demande — essentiel pour les grosses applications SaaS. L'utilisateur ne télécharge que ce dont il a besoin.

Guards : Fonctions qui contrôlent l'accès aux routes. canActivate pour protéger (ex: authentification), canDeactivate pour confirmer la navigation (ex: formulaire non sauvegardé).

routerLink : Remplace les <a href> pour la navigation interne — pas de rechargement de page.
// app.routes.ts
import { Routes } from '@angular/router';

export const routes: Routes = [
{ path: ‘’, component: HomeComponent },
{
path: ‘dashboard’,
// Lazy loading — chargé à la demande
loadComponent: () =>
import(’./dashboard/dashboard.component’)
.then(m => m.DashboardComponent),
// Guard — accès authentifié
canActivate: [authGuard]
},
{
path: ‘crypto/:id’,
loadComponent: () =>
import(’./crypto-detail/crypto-detail.component’)
.then(m => m.CryptoDetailComponent)
},
{ path: ‘**’, component: NotFoundComponent }
];

// auth.guard.ts — Guard fonctionnel
import { inject } from ‘@angular/core’;
import { Router } from ‘@angular/router’;

export const authGuard = () => {
const auth = inject(AuthService);
const router = inject(Router);

if (auth.isAuthenticated()) return true;
return router.parseUrl(’/login’);
};

// Dans un template
// 
//   Dashboard
// 
//