Files
2026-10-16 17:02:38 +02:00

1432 lines
58 KiB
HTML
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!DOCTYPE html>
<!--
=====================================================================
index.html — la STRUCTURE de la page
---------------------------------------------------------------------
Une page web, c'est (presque toujours) TROIS langages qui coopèrent :
HTML → le CONTENU et sa structure (ce fichier) "le squelette"
CSS → l'APPARENCE (style.css) "la peau"
JS → le COMPORTEMENT (script.js) "les muscles"
Le HTML est fait de BALISES : <nom attribut="valeur"> contenu </nom>
Certaines balises n'ont pas de fermeture : <meta>, <link>, <img>…
Ceci est un COMMENTAIRE HTML : le navigateur l'ignore complètement.
=====================================================================
-->
<html lang="fr"> <!-- lang="fr" : aide les lecteurs d'écran et la traduction -->
<head>
<!-- Le <head> contient les infos SUR la page (invisibles à l'écran) -->
<!-- Encodage des caractères : indispensable pour les accents é, à, ç… -->
<meta charset="UTF-8">
<!-- Indispensable sur mobile : la page s'adapte à la largeur de l'écran -->
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<!-- Le titre affiché dans l'onglet du navigateur -->
<title>Intro JavaScript</title>
<!-- On relie la feuille de style CSS -->
<link rel="stylesheet" href="style.css">
<!--
On relie le script JS. L'attribut "defer" signifie :
"télécharge-le tout de suite, mais attends que le HTML soit
entièrement lu avant de l'exécuter". Sans ça, le script pourrait
chercher des éléments qui n'existent pas encore.
-->
<script src="script.js" defer></script>
</head>
<body>
<!-- Le <body> contient tout ce qui est VISIBLE -->
<div class="mise-en-page">
<!-- ============================ MENU ============================ -->
<!-- <nav> = zone de navigation. Les liens href="#xxx" mènent à l'élément id="xxx" -->
<nav class="sommaire" aria-label="Sommaire">
<div class="logo"><span>JS</span> Intro au code</div>
<ol>
<li><a href="#ch0">Coder, c'est quoi ?</a></li>
<li><a href="#ch1">Console & commentaires</a></li>
<li><a href="#ch2">Variables</a></li>
<li><a href="#ch3">Types de données</a></li>
<li><a href="#ch4">Opérateurs</a></li>
<li><a href="#ch5">Conditions</a></li>
<li><a href="#ch6">Boucles</a></li>
<li><a href="#ch7">Fonctions</a></li>
<li><a href="#ch8">Tableaux</a></li>
<li><a href="#ch9">Objets</a></li>
<li><a href="#ch10">Le DOM</a></li>
<li><a href="#ch11">Événements</a></li>
<li><a href="#ch12">Asynchrone</a></li>
<li><a href="#ch13">Classes</a></li>
<li><a href="#ch14">Mini-projet</a></li>
<li><a href="#ch15">Et après ?</a></li>
</ol>
<button id="bouton-theme" type="button">◐ Clair / sombre</button>
</nav>
<!-- ========================== CONTENU ========================== -->
<main>
<header class="intro">
<h1>Apprendre à coder avec <mark>JavaScript</mark></h1>
<p class="chapeau">
On part de zéro, on va loin. Chaque exemple est <strong>modifiable</strong> et
<strong>exécutable</strong> directement dans la page : lis, change, casse, recommence.
</p>
<div class="encadre astuce">
<strong>Comment utiliser cette page</strong>
Dans chaque bloc noir, modifie le code puis clique sur <code>▶ Exécuter</code>
(ou <code>Ctrl + Entrée</code>). Le bouton <code>↺</code> remet l'exemple d'origine.
Tout ce qui suit <code>//</code> est un commentaire : lis-les, ils expliquent tout.
</div>
</header>
<!-- ======================================================== -->
<section class="chapitre" id="ch0">
<h2><span class="num">00</span>Coder, c'est quoi ?</h2>
<p>
Un ordinateur est extrêmement rapide mais complètement <strong>bête</strong> :
il fait exactement ce qu'on lui dit, ligne par ligne, sans jamais deviner ce qu'on
« voulait dire ». <strong>Coder</strong>, c'est écrire ces instructions dans
un langage précis qu'il comprend.
</p>
<p>
<strong>JavaScript</strong> (JS) est le langage des navigateurs web. Toutes les pages
interactives que tu utilises (menus, formulaires, jeux, cartes…) en contiennent.
Il tourne aussi sur des serveurs (Node.js), dans des applis, des objets connectés…
</p>
<h3>Les 3 couches d'une page web</h3>
<pre class="schema">
┌────────────┐ ┌────────────┐ ┌────────────────┐
│ HTML │ │ CSS │ │ JavaScript │
│ le contenu │ + │ l'apparence│ + │ le comportement│
│ "un titre" │ │ "en rouge" │ │ "si on clique, │
│ │ │ │ │ il grossit" │
└────────────┘ └────────────┘ └────────────────┘
index.html style.css script.js
</pre>
<h3>Un programme = des instructions, dans l'ordre</h3>
<p>
Le code se lit <strong>de haut en bas</strong>. Chaque ligne est une instruction,
généralement terminée par un point-virgule <code>;</code>.
Essaie : clique sur Exécuter.
</p>
<div class="bac">
<div class="barre"><span>premier-programme.js</span>
<div class="boutons"><button class="reinit" type="button">↺</button><button class="executer" type="button">▶ Exécuter</button></div></div>
<textarea aria-label="Éditeur de code">
// Ceci est un commentaire : l'ordinateur l'ignore.
// Il sert aux HUMAINS qui lisent le code.
console.log("Bonjour !"); // 1re instruction
console.log("Je suis un programme"); // 2e instruction
console.log(2 + 3); // 3e : JS sait calculer
</textarea>
<div class="sortie" aria-live="polite"></div>
</div>
<div class="encadre">
<strong>La console du navigateur</strong>
Appuie sur <code>F12</code> (ou clic droit → Inspecter) puis onglet « Console ».
C'est l'outil n°1 du développeur : on y voit les messages et les erreurs.
Tu peux même y taper du JavaScript directement.
</div>
</section>
<!-- ======================================================== -->
<section class="chapitre" id="ch1">
<h2><span class="num">01</span>La console & les commentaires</h2>
<p>
<code>console.log(...)</code> affiche ce qu'on met entre les parenthèses.
C'est ton meilleur ami pour <strong>comprendre ce qui se passe</strong> dans ton code :
quand quelque chose ne marche pas, on affiche des valeurs pour vérifier.
</p>
<div class="bac">
<div class="barre"><span>console.js</span>
<div class="boutons"><button class="reinit" type="button">↺</button><button class="executer" type="button">▶ Exécuter</button></div></div>
<textarea aria-label="Éditeur de code">
// Commentaire sur une ligne : tout ce qui suit // est ignoré
/*
Commentaire sur
plusieurs lignes :
tout ce qui est entre la barre-étoile d'ouverture
et l'étoile-barre de fermeture est ignoré
*/
console.log("Du texte"); // un texte s'écrit entre guillemets
console.log(42); // un nombre s'écrit sans guillemets
console.log("A", "B", 3); // plusieurs valeurs séparées par des virgules
console.warn("Un avertissement"); // variantes : warn, error, info
console.error("Une erreur (pour de faux)");
console.info("Une information");
// À toi : affiche ton prénom sur la ligne suivante
</textarea>
<div class="sortie" aria-live="polite"></div>
</div>
<div class="encadre astuce">
<strong>Bonne pratique</strong>
Un bon commentaire explique <em>pourquoi</em> on fait quelque chose, pas seulement
<em>quoi</em>. Le code dit déjà « quoi » ; le commentaire raconte l'intention.
</div>
</section>
<!-- ======================================================== -->
<section class="chapitre" id="ch2">
<h2><span class="num">02</span>Les variables : des boîtes avec une étiquette</h2>
<p>
Une <strong>variable</strong> est une boîte qui porte un nom et contient une valeur.
On la crée (on dit <em>déclare</em>) une fois, puis on l'utilise par son nom.
</p>
<pre class="schema">
let age = 20;
┌─────────┐
│ 20 │ ← la valeur (ce qu'il y a dedans)
└─────────┘
age ← l'étiquette (le nom de la variable)
</pre>
<table>
<tr><th>Mot-clé</th><th>Peut-on changer la valeur ?</th><th>Quand l'utiliser</th></tr>
<tr><td><code>const</code></td><td>Non</td><td>Par défaut, tout le temps</td></tr>
<tr><td><code>let</code></td><td>Oui</td><td>Quand la valeur doit évoluer (compteur, score…)</td></tr>
<tr><td><code>var</code></td><td>Oui</td><td>Jamais : ancienne syntaxe, comportements piégeux</td></tr>
</table>
<div class="bac">
<div class="barre"><span>variables.js</span>
<div class="boutons"><button class="reinit" type="button">↺</button><button class="executer" type="button">▶ Exécuter</button></div></div>
<textarea aria-label="Éditeur de code">
// "let" crée une variable dont la valeur peut changer
let score = 0;
console.log("Score de départ :", score);
score = 10; // on REMPLACE la valeur (pas de "let" cette fois !)
console.log("Score après :", score);
score = score + 5; // on prend l'ancienne valeur, on ajoute 5, on range
console.log("Score + 5 :", score);
// "const" crée une constante : sa valeur ne changera JAMAIS
const prenom = "Ada";
console.log("Bonjour", prenom);
// Décommente la ligne suivante (enlève les //) et exécute : erreur !
// prenom = "Alan";
// Règles de nommage :
// - pas d'espace, pas de tiret, ne commence pas par un chiffre
// - sensible à la casse : age ≠ Age
// - convention "camelCase" : nombreDeVies, prixTotal
const nombreDeVies = 3;
console.log(nombreDeVies);
</textarea>
<div class="sortie" aria-live="polite"></div>
</div>
<h3>La portée (scope) : où une variable existe</h3>
<p>
Une variable déclarée avec <code>let</code> ou <code>const</code> n'existe que
<strong>dans le bloc <code>{ }</code></strong> où elle est créée.
En dehors, elle est invisible.
</p>
<div class="bac">
<div class="barre"><span>portee.js</span>
<div class="boutons"><button class="reinit" type="button">↺</button><button class="executer" type="button">▶ Exécuter</button></div></div>
<textarea aria-label="Éditeur de code">
const dehors = "je suis visible partout dans ce code";
{
// Ceci est un bloc. Ce qui est créé ici reste ici.
const dedans = "je n'existe que dans ce bloc";
console.log(dehors); // ✔ on voit ce qui est à l'extérieur
console.log(dedans); // ✔
}
console.log(dehors); // ✔
console.log(dedans); // ✖ ReferenceError : "dedans" n'existe pas ici
</textarea>
<div class="sortie" aria-live="polite"></div>
</div>
</section>
<!-- ======================================================== -->
<section class="chapitre" id="ch3">
<h2><span class="num">03</span>Les types de données</h2>
<p>Toute valeur a un <strong>type</strong>. Les principaux :</p>
<table>
<tr><th>Type</th><th>Exemple</th><th>C'est quoi</th></tr>
<tr><td><code>string</code></td><td><code>"bonjour"</code></td><td>Du texte (chaîne de caractères)</td></tr>
<tr><td><code>number</code></td><td><code>42</code>, <code>3.14</code></td><td>Un nombre (entier ou à virgule, avec un point)</td></tr>
<tr><td><code>boolean</code></td><td><code>true</code>, <code>false</code></td><td>Vrai ou faux</td></tr>
<tr><td><code>undefined</code></td><td><code>undefined</code></td><td>« Pas encore de valeur »</td></tr>
<tr><td><code>null</code></td><td><code>null</code></td><td>« Vide, volontairement »</td></tr>
<tr><td><code>object</code></td><td><code>{ }</code>, <code>[ ]</code></td><td>Une structure qui regroupe des valeurs (chap. 8 et 9)</td></tr>
</table>
<div class="bac">
<div class="barre"><span>types.js</span>
<div class="boutons"><button class="reinit" type="button">↺</button><button class="executer" type="button">▶ Exécuter</button></div></div>
<textarea aria-label="Éditeur de code">
// typeof permet de connaître le type d'une valeur
console.log(typeof "salut"); // "string"
console.log(typeof 12); // "number"
console.log(typeof true); // "boolean"
console.log(typeof undefined); // "undefined"
let pasEncore; // déclarée mais jamais remplie
console.log(pasEncore); // undefined
// --- Les textes (strings) ---
// 3 sortes de guillemets : "doubles", 'simples', `backticks`
const ville = "Le Havre";
const phrase1 = "J'habite au " + ville; // + colle les textes (concaténation)
const phrase2 = `J'habite au ${ville}`; // gabarit : ${...} insère une valeur
console.log(phrase1);
console.log(phrase2);
console.log(`2 + 2 = ${2 + 2}`); // on peut même calculer dedans
// Les strings ont des "méthodes" : des actions qu'on leur demande
console.log(ville.length); // nombre de caractères
console.log(ville.toUpperCase()); // en majuscules
console.log(ville.includes("Havre"));// contient "Havre" ? → true
console.log(ville[0]); // 1er caractère (on compte à partir de 0 !)
// --- Conversion de types ---
console.log("5" + 3); // "53" ← piège : + avec un texte = collage !
console.log("5" * 3); // 15 ← * force la conversion en nombre
console.log(Number("5") + 3); // 8 ← on convertit explicitement : plus clair
console.log(String(42)); // "42"
</textarea>
<div class="sortie" aria-live="polite"></div>
</div>
<div class="encadre attention">
<strong>Piège classique</strong>
Ce qu'on récupère d'un champ de formulaire est <em>toujours</em> du texte,
même si l'utilisateur tape un nombre. Pense à le convertir avec <code>Number()</code>.
</div>
</section>
<!-- ======================================================== -->
<section class="chapitre" id="ch4">
<h2><span class="num">04</span>Les opérateurs</h2>
<div class="bac">
<div class="barre"><span>operateurs.js</span>
<div class="boutons"><button class="reinit" type="button">↺</button><button class="executer" type="button">▶ Exécuter</button></div></div>
<textarea aria-label="Éditeur de code">
// --- Arithmétique ---
console.log(7 + 2); // 9 addition
console.log(7 - 2); // 5 soustraction
console.log(7 * 2); // 14 multiplication
console.log(7 / 2); // 3.5 division
console.log(7 % 2); // 1 MODULO : le reste de la division (7 = 3×2 + 1)
console.log(2 ** 3); // 8 puissance (2×2×2)
// Le modulo sert souvent à savoir si un nombre est pair :
console.log(10 % 2 === 0); // true → 10 est pair
// --- Raccourcis d'affectation ---
let n = 10;
n += 5; // pareil que n = n + 5 → 15
n -= 3; // n = n - 3 → 12
n *= 2; // n = n * 2 → 24
n++; // n = n + 1 → 25
console.log(n);
// --- Comparaison : le résultat est TOUJOURS un booléen ---
console.log(5 > 3); // true
console.log(5 <= 3); // false
console.log(5 === 5); // true strictement égal (même valeur ET même type)
console.log(5 !== 4); // true différent
// ⚠ == (double égal) convertit les types avant de comparer : piégeux !
console.log(5 == "5"); // true 😬
console.log(5 === "5"); // false ✔ utilise TOUJOURS ===
// --- Logique : combiner des conditions ---
const aFaim = true;
const aDeLArgent = false;
console.log(aFaim && aDeLArgent); // ET : vrai seulement si les DEUX sont vrais → false
console.log(aFaim || aDeLArgent); // OU : vrai si AU MOINS UN est vrai → true
console.log(!aFaim); // NON : inverse → false
</textarea>
<div class="sortie" aria-live="polite"></div>
</div>
<div class="exercice">
<strong>Exercice</strong> — Une pizza coûte 12 €, on en commande 3, et on a un bon de
réduction de 20 %. Calcule et affiche le prix final avec des variables bien nommées.
<details>
<summary>Voir une solution</summary>
<div class="bac">
<div class="barre"><span>solution.js</span>
<div class="boutons"><button class="reinit" type="button">↺</button><button class="executer" type="button">▶ Exécuter</button></div></div>
<textarea aria-label="Éditeur de code">
const prixPizza = 12;
const quantite = 3;
const reduction = 0.20; // 20 % = 20 / 100
const total = prixPizza * quantite; // 36
const prixFinal = total * (1 - reduction); // on paie 80 % du total
console.log(`Prix final : ${prixFinal} €`);
</textarea>
<div class="sortie" aria-live="polite"></div>
</div>
</details>
</div>
</section>
<!-- ======================================================== -->
<section class="chapitre" id="ch5">
<h2><span class="num">05</span>Les conditions : prendre des décisions</h2>
<p>
Un programme doit souvent choisir : <em>si</em> quelque chose est vrai, faire ceci,
<em>sinon</em> faire cela.
</p>
<pre class="schema">
┌──────────────┐
│ age >= 18 ? │
└──────┬───────┘
oui ┌────┴────┐ non
▼ ▼
"majeur" "mineur"
</pre>
<div class="bac">
<div class="barre"><span>conditions.js</span>
<div class="boutons"><button class="reinit" type="button">↺</button><button class="executer" type="button">▶ Exécuter</button></div></div>
<textarea aria-label="Éditeur de code">
const age = 16; // ← change cette valeur et ré-exécute
// if (condition) { ... } else { ... }
if (age >= 18) {
// ce bloc s'exécute seulement si la condition est vraie
console.log("Tu es majeur·e");
} else {
// sinon, c'est celui-ci
console.log("Tu es mineur·e");
}
// Plusieurs cas : else if
const note = 14;
if (note >= 16) {
console.log("Très bien");
} else if (note >= 12) {
console.log("Bien"); // ← on s'arrête au PREMIER cas vrai
} else if (note >= 10) {
console.log("Passable");
} else {
console.log("Insuffisant");
}
// L'opérateur ternaire : un if/else compact pour choisir une VALEUR
// condition ? valeurSiVrai : valeurSiFaux
const statut = age >= 18 ? "adulte" : "enfant";
console.log(statut);
// Valeurs "truthy" / "falsy" : dans un if, toute valeur devient vrai ou faux.
// Sont FAUSSES : false, 0, "" (texte vide), null, undefined, NaN
// Tout le reste est VRAI.
const pseudo = "";
if (pseudo) {
console.log("Bienvenue " + pseudo);
} else {
console.log("Tu n'as pas de pseudo !");
}
</textarea>
<div class="sortie" aria-live="polite"></div>
</div>
<h3>switch : comparer une valeur à plusieurs cas précis</h3>
<div class="bac">
<div class="barre"><span>switch.js</span>
<div class="boutons"><button class="reinit" type="button">↺</button><button class="executer" type="button">▶ Exécuter</button></div></div>
<textarea aria-label="Éditeur de code">
const jour = "samedi";
switch (jour) {
case "samedi":
case "dimanche": // deux cas qui partagent le même code
console.log("Week-end ! 🎉");
break; // ⚠ "break" stoppe le switch, sinon on continue dans le cas suivant
case "mercredi":
console.log("Club info !");
break;
default: // si aucun cas ne correspond
console.log("Jour de cours");
}
</textarea>
<div class="sortie" aria-live="polite"></div>
</div>
</section>
<!-- ======================================================== -->
<section class="chapitre" id="ch6">
<h2><span class="num">06</span>Les boucles : répéter sans se répéter</h2>
<p>
Afficher les nombres de 1 à 1000 ? On ne va pas écrire 1000 lignes.
Une <strong>boucle</strong> répète un bloc de code tant qu'une condition est vraie.
</p>
<div class="bac">
<div class="barre"><span>boucles.js</span>
<div class="boutons"><button class="reinit" type="button">↺</button><button class="executer" type="button">▶ Exécuter</button></div></div>
<textarea aria-label="Éditeur de code">
// --- La boucle for : quand on sait combien de fois répéter ---
// for (départ ; condition pour continuer ; étape après chaque tour)
for (let i = 1; i <= 5; i++) {
console.log("Tour n°" + i);
}
// Déroulé : i=1 → affiche → i++ (i=2) → 2<=5 ? oui → affiche → … → i=6 → 6<=5 ? non → fin
// --- La boucle while : tant que la condition est vraie ---
let pieces = 3;
while (pieces > 0) {
console.log(`Il reste ${pieces} pièce(s)`);
pieces--; // ⚠ sans cette ligne : BOUCLE INFINIE, la page gèle !
}
console.log("Plus de pièces.");
// --- break et continue ---
for (let i = 1; i <= 10; i++) {
if (i % 2 === 0) continue; // continue : saute au tour suivant (on ignore les pairs)
if (i > 7) break; // break : sort complètement de la boucle
console.log("impair :", i);
}
// --- Boucles imbriquées : une table de multiplication ---
for (let ligne = 1; ligne <= 3; ligne++) {
let texte = "";
for (let col = 1; col <= 5; col++) {
texte += (ligne * col) + "\t"; // \t = tabulation
}
console.log(texte);
}
</textarea>
<div class="sortie" aria-live="polite"></div>
</div>
<div class="exercice">
<strong>Exercice : FizzBuzz</strong> (un classique des entretiens d'embauche !) —
Affiche les nombres de 1 à 20, mais : remplace les multiples de 3 par « Fizz »,
ceux de 5 par « Buzz », et ceux de 3 <em>et</em> 5 par « FizzBuzz ».
<details>
<summary>Un indice</summary>
<p>Utilise le modulo <code>%</code>. Et teste d'abord le cas « 3 ET 5 »… pourquoi ?</p>
</details>
<details>
<summary>Voir une solution</summary>
<div class="bac">
<div class="barre"><span>fizzbuzz.js</span>
<div class="boutons"><button class="reinit" type="button">↺</button><button class="executer" type="button">▶ Exécuter</button></div></div>
<textarea aria-label="Éditeur de code">
for (let i = 1; i <= 20; i++) {
// On teste le cas le plus précis en PREMIER,
// sinon 15 serait attrapé par "multiple de 3" et s'arrêterait là.
if (i % 3 === 0 && i % 5 === 0) {
console.log("FizzBuzz");
} else if (i % 3 === 0) {
console.log("Fizz");
} else if (i % 5 === 0) {
console.log("Buzz");
} else {
console.log(i);
}
}
</textarea>
<div class="sortie" aria-live="polite"></div>
</div>
</details>
</div>
</section>
<!-- ======================================================== -->
<section class="chapitre" id="ch7">
<h2><span class="num">07</span>Les fonctions : des recettes réutilisables</h2>
<p>
Une <strong>fonction</strong> est un morceau de code auquel on donne un nom, pour
pouvoir le lancer (on dit <em>appeler</em>) autant de fois qu'on veut.
Elle peut recevoir des <strong>paramètres</strong> (les ingrédients) et
<strong>renvoyer</strong> un résultat (le plat).
</p>
<pre class="schema">
paramètres fonction valeur renvoyée
(3, 4) ───▶ ┌──────────────┐ ───▶ 7
│ additionner │
└──────────────┘
</pre>
<div class="bac">
<div class="barre"><span>fonctions.js</span>
<div class="boutons"><button class="reinit" type="button">↺</button><button class="executer" type="button">▶ Exécuter</button></div></div>
<textarea aria-label="Éditeur de code">
// 1. DÉCLARER la fonction (on écrit la recette, rien ne s'exécute encore)
function direBonjour(prenom) { // "prenom" est un PARAMÈTRE
console.log(`Bonjour ${prenom} !`);
}
// 2. APPELER la fonction (on cuisine) : nom + parenthèses
direBonjour("Ada"); // "Ada" est un ARGUMENT
direBonjour("Alan");
// --- return : renvoyer un résultat ---
function additionner(a, b) {
return a + b; // return renvoie la valeur ET arrête la fonction
console.log("jamais affiché"); // code mort : après un return, plus rien ne s'exécute
}
const resultat = additionner(3, 4); // on récupère ce qui est renvoyé
console.log(resultat); // 7
console.log(additionner(10, additionner(1, 2))); // on peut imbriquer : 13
// Sans return, une fonction renvoie undefined
console.log(direBonjour("Grace")); // affiche le bonjour, PUIS undefined
// --- Paramètre par défaut ---
function saluer(nom = "inconnu·e") {
return "Salut " + nom;
}
console.log(saluer()); // "Salut inconnu·e"
console.log(saluer("Linus"));
// --- Fonction fléchée (arrow function) : syntaxe courte, très utilisée ---
const carre = (x) => x * x; // si une seule expression : return implicite
const auCube = x => { // avec des accolades : return obligatoire
const c = x * x * x;
return c;
};
console.log(carre(5), auCube(3));
</textarea>
<div class="sortie" aria-live="polite"></div>
</div>
<h3>Les fonctions sont des valeurs</h3>
<p>
En JS, une fonction peut être rangée dans une variable, ou <strong>passée en
argument</strong> à une autre fonction. Une fonction passée ainsi s'appelle un
<em>callback</em> (« rappel »). C'est une idée centrale en JavaScript.
</p>
<div class="bac">
<div class="barre"><span>callbacks.js</span>
<div class="boutons"><button class="reinit" type="button">↺</button><button class="executer" type="button">▶ Exécuter</button></div></div>
<textarea aria-label="Éditeur de code">
// Cette fonction reçoit une AUTRE fonction en paramètre ("action")
function repeter(fois, action) {
for (let i = 0; i < fois; i++) {
action(i); // on appelle la fonction reçue
}
}
repeter(3, (numero) => console.log("Hip hip hip… hourra !", numero));
// Une fonction peut aussi FABRIQUER et renvoyer une fonction
function creerMultiplicateur(facteur) {
// La fonction renvoyée "se souvient" de facteur : c'est une CLOSURE (fermeture)
return (nombre) => nombre * facteur;
}
const doubler = creerMultiplicateur(2);
const tripler = creerMultiplicateur(3);
console.log(doubler(10), tripler(10)); // 20 30
// --- Récursivité : une fonction qui s'appelle elle-même ---
// factorielle(4) = 4 × 3 × 2 × 1
function factorielle(n) {
if (n <= 1) return 1; // le CAS DE BASE : indispensable pour s'arrêter !
return n * factorielle(n - 1); // on réduit le problème à chaque appel
}
console.log(factorielle(5)); // 120
</textarea>
<div class="sortie" aria-live="polite"></div>
</div>
<div class="exercice">
<strong>Exercice</strong> — Écris une fonction <code>estPair(n)</code> qui renvoie
<code>true</code> ou <code>false</code>, puis une fonction <code>maximum(a, b)</code>
qui renvoie le plus grand des deux nombres.
<details>
<summary>Voir une solution</summary>
<div class="bac">
<div class="barre"><span>solution.js</span>
<div class="boutons"><button class="reinit" type="button">↺</button><button class="executer" type="button">▶ Exécuter</button></div></div>
<textarea aria-label="Éditeur de code">
// Une comparaison donne déjà un booléen : pas besoin de if !
const estPair = (n) => n % 2 === 0;
function maximum(a, b) {
return a > b ? a : b; // ternaire
}
console.log(estPair(4), estPair(7)); // true false
console.log(maximum(3, 9)); // 9
</textarea>
<div class="sortie" aria-live="polite"></div>
</div>
</details>
</div>
</section>
<!-- ======================================================== -->
<section class="chapitre" id="ch8">
<h2><span class="num">08</span>Les tableaux : des listes de valeurs</h2>
<p>
Un <strong>tableau</strong> (<em>array</em>) range plusieurs valeurs dans l'ordre.
Chaque case a un numéro, l'<strong>indice</strong>, qui commence à <strong>0</strong>.
</p>
<pre class="schema">
const fruits = ["pomme", "kiwi", "poire"];
indice : 0 1 2
┌───────┬───────┬───────┐
│ pomme │ kiwi │ poire │ fruits.length → 3
└───────┴───────┴───────┘
</pre>
<div class="bac">
<div class="barre"><span>tableaux.js</span>
<div class="boutons"><button class="reinit" type="button">↺</button><button class="executer" type="button">▶ Exécuter</button></div></div>
<textarea aria-label="Éditeur de code">
const fruits = ["pomme", "kiwi", "poire"];
console.log(fruits[0]); // "pomme" (1er élément)
console.log(fruits.length); // 3
console.log(fruits[fruits.length - 1]); // le DERNIER élément
console.log(fruits[10]); // undefined : la case n'existe pas
// Modifier
fruits[1] = "mangue"; // remplace "kiwi"
fruits.push("banane"); // ajoute à la FIN
fruits.unshift("fraise"); // ajoute au DÉBUT
console.log(fruits);
const dernier = fruits.pop(); // retire (et renvoie) le dernier
console.log("retiré :", dernier, "→", fruits);
// Rechercher
console.log(fruits.includes("poire")); // true
console.log(fruits.indexOf("poire")); // sa position (-1 si absent)
// Parcourir : for...of donne directement chaque élément
for (const fruit of fruits) {
console.log("J'aime la " + fruit);
}
// 💡 Pourquoi "const" alors qu'on modifie le tableau ?
// const empêche de remplacer la BOÎTE (fruits = autre chose),
// mais on peut changer son CONTENU.
</textarea>
<div class="sortie" aria-live="polite"></div>
</div>
<h3>Les super-pouvoirs : map, filter, reduce…</h3>
<p>
Ces méthodes prennent une <strong>fonction</strong> (un callback, vu au chapitre 7)
et l'appliquent à chaque élément. Elles ne modifient pas le tableau d'origine :
elles en <strong>renvoient un nouveau</strong>. C'est le style « moderne » de JS.
</p>
<div class="bac">
<div class="barre"><span>map-filter-reduce.js</span>
<div class="boutons"><button class="reinit" type="button">↺</button><button class="executer" type="button">▶ Exécuter</button></div></div>
<textarea aria-label="Éditeur de code">
const notes = [12, 8, 15, 19, 6, 11];
// forEach : fait quelque chose pour chaque élément (ne renvoie rien)
notes.forEach((note, indice) => console.log(`Élève ${indice} : ${note}`));
// map : TRANSFORME chaque élément → nouveau tableau de même taille
const notesSur100 = notes.map(note => note * 5);
console.log("sur 100 :", notesSur100);
// filter : GARDE seulement les éléments pour lesquels la fonction renvoie true
const reussites = notes.filter(note => note >= 10);
console.log("≥ 10 :", reussites);
// find : renvoie le PREMIER élément qui correspond
console.log("1re note > 14 :", notes.find(note => note > 14));
// reduce : RÉDUIT le tableau à une seule valeur (ici : la somme)
// acc = l'accumulateur (le résultat en cours), 0 = sa valeur de départ
const somme = notes.reduce((acc, note) => acc + note, 0);
console.log("somme :", somme, "moyenne :", (somme / notes.length).toFixed(2));
// sort : trie (⚠ modifie le tableau ! on copie d'abord avec [...notes])
const triees = [...notes].sort((a, b) => a - b);
console.log("triées :", triees);
// On peut ENCHAÎNER les méthodes :
const resultat = notes
.filter(n => n >= 10) // on garde les réussites
.map(n => n + 1) // on ajoute un point bonus
.join(" / "); // on colle en un seul texte
console.log(resultat);
</textarea>
<div class="sortie" aria-live="polite"></div>
</div>
</section>
<!-- ======================================================== -->
<section class="chapitre" id="ch9">
<h2><span class="num">09</span>Les objets : décrire une chose</h2>
<p>
Un tableau range des valeurs <em>par position</em>. Un <strong>objet</strong> les
range <em>par nom</em> : des paires <code>clé: valeur</code> qu'on appelle
<strong>propriétés</strong>. Idéal pour décrire un utilisateur, un produit, un personnage…
</p>
<div class="bac">
<div class="barre"><span>objets.js</span>
<div class="boutons"><button class="reinit" type="button">↺</button><button class="executer" type="button">▶ Exécuter</button></div></div>
<textarea aria-label="Éditeur de code">
const perso = {
nom: "Link", // clé "nom", valeur "Link"
vie: 3,
inventaire: ["épée", "bouclier"], // une valeur peut être un tableau…
position: { x: 10, y: 4 }, // …ou un autre objet
// Une fonction dans un objet s'appelle une MÉTHODE
sePresenter() {
// "this" désigne l'objet lui-même
return `Je suis ${this.nom}, j'ai ${this.vie} cœurs.`;
},
};
// Lire une propriété : notation pointée
console.log(perso.nom);
console.log(perso.position.x);
console.log(perso.inventaire[0]);
// Notation crochets : utile quand le nom de la clé est dans une variable
const cle = "vie";
console.log(perso[cle]);
// Modifier / ajouter / supprimer
perso.vie -= 1; // modifie
perso.niveau = 1; // ajoute une nouvelle propriété
delete perso.position; // supprime
console.log(perso.sePresenter());
console.log(perso);
// Parcourir les clés
for (const k in perso) {
console.log("clé :", k);
}
console.log(Object.keys(perso)); // tableau des clés
</textarea>
<div class="sortie" aria-live="polite"></div>
</div>
<h3>Syntaxes modernes très courantes</h3>
<div class="bac">
<div class="barre"><span>moderne.js</span>
<div class="boutons"><button class="reinit" type="button">↺</button><button class="executer" type="button">▶ Exécuter</button></div></div>
<textarea aria-label="Éditeur de code">
const film = { titre: "Akira", annee: 1988, realisateur: "Ōtomo" };
// DÉSTRUCTURATION : extraire des propriétés dans des variables
const { titre, annee } = film;
console.log(titre, annee);
// Fonctionne aussi avec les tableaux (par position)
const [premier, second] = ["or", "argent", "bronze"];
console.log(premier, second);
// SPREAD (...) : "étaler" le contenu pour copier / fusionner
const filmComplet = { ...film, genre: "animation" }; // copie + ajout
console.log(filmComplet);
const tous = [...[1, 2], ...[3, 4]];
console.log(tous);
// CHAÎNAGE OPTIONNEL ?. : évite l'erreur si une propriété n'existe pas
console.log(film.suite?.titre); // undefined (au lieu d'une TypeError)
// Un tableau d'objets : LA structure de données la plus courante sur le web
const eleves = [
{ nom: "Inès", age: 19 },
{ nom: "Tom", age: 22 },
{ nom: "Léa", age: 20 },
];
const noms = eleves.filter(e => e.age >= 20).map(e => e.nom);
console.log(noms);
// JSON : le format texte pour échanger des données (avec un serveur, un fichier…)
const texteJSON = JSON.stringify(eleves[0]); // objet → texte
console.log(texteJSON, typeof texteJSON);
const objetRelu = JSON.parse('{"nom":"Sam","age":21}'); // texte → objet
console.log(objetRelu.nom);
</textarea>
<div class="sortie" aria-live="polite"></div>
</div>
<div class="encadre attention">
<strong>Copie ou référence ?</strong>
<code>const b = a;</code> ne copie <em>pas</em> un objet ou un tableau : <code>a</code>
et <code>b</code> désignent alors <em>le même</em> objet. Modifier l'un modifie l'autre.
Pour copier : <code>const b = { ...a };</code> ou <code>[...a]</code>.
</div>
</section>
<!-- ======================================================== -->
<section class="chapitre" id="ch10">
<h2><span class="num">10</span>Le DOM : piloter la page avec JS</h2>
<p>
Quand le navigateur lit le HTML, il construit en mémoire un <strong>arbre
d'objets</strong> : le <strong>DOM</strong> (<em>Document Object Model</em>).
JavaScript peut lire et modifier cet arbre… et la page change instantanément à l'écran.
</p>
<pre class="schema">
document
└── html
├── head
│ └── title
└── body
├── h1 ← document.querySelector("h1")
└── div.carte ← document.querySelector(".carte")
└── p
</pre>
<div class="encadre">
<strong>Note sur les exemples</strong>
Dans une vraie page, on cherche les éléments dans <code>document</code>.
Ici, chaque exemple a sa petite zone blanche nommée <code>scene</code> : on écrit
<code>scene.querySelector(...)</code> pour ne toucher qu'elle. Le principe est identique.
</div>
<div class="bac">
<div class="barre"><span>dom.js</span>
<div class="boutons"><button class="reinit" type="button">↺</button><button class="executer" type="button">▶ Exécuter</button></div></div>
<textarea aria-label="Éditeur de code">
// 1. SÉLECTIONNER un élément avec un sélecteur CSS (comme dans style.css)
const titre = scene.querySelector("h4"); // par balise
const boite = scene.querySelector(".boite"); // par classe
const items = scene.querySelectorAll("li"); // TOUS les <li>
console.log(titre, boite, items.length);
// 2. MODIFIER le texte
titre.textContent = "Titre modifié par JavaScript ✨";
// 3. MODIFIER le style (propriétés CSS en camelCase : background-color → backgroundColor)
boite.style.backgroundColor = "#d4a017";
boite.style.padding = "12px";
boite.style.borderRadius = "8px";
// 4. AJOUTER / RETIRER des classes CSS (mieux que style : on garde le CSS dans le CSS)
boite.classList.add("important");
console.log(boite.classList.contains("important")); // true
// 5. MODIFIER chaque élément d'une liste
items.forEach((li, i) => {
li.textContent = `Élément n°${i + 1} (modifié)`;
});
// 6. CRÉER un nouvel élément et l'ajouter dans la page
const nouveau = document.createElement("p"); // crée <p></p> (pas encore affiché)
nouveau.textContent = "Je viens d'être créé !";
scene.append(nouveau); // l'insère à la fin de la scène
// 7. Lire / modifier un attribut
const lien = scene.querySelector("a");
lien.setAttribute("href", "https://developer.mozilla.org/fr/");
lien.textContent = "Documentation MDN";
</textarea>
<div class="sortie" aria-live="polite"></div>
<div class="scene">
<h4>Un titre</h4>
<div class="boite">Une boîte</div>
<ul><li>un</li><li>deux</li><li>trois</li></ul>
<a href="#">un lien</a>
</div>
</div>
<div class="encadre attention">
<strong>textContent ou innerHTML ?</strong>
<code>innerHTML</code> interprète le texte comme du HTML (<code>"&lt;b&gt;gras&lt;/b&gt;"</code>
devient <b>gras</b>). Pratique, mais dangereux avec du texte tapé par un utilisateur :
il pourrait injecter du code (faille « XSS »). Par défaut, utilise <code>textContent</code>.
</div>
</section>
<!-- ======================================================== -->
<section class="chapitre" id="ch11">
<h2><span class="num">11</span>Les événements : réagir à l'utilisateur</h2>
<p>
Un <strong>événement</strong>, c'est quelque chose qui se produit : un clic, une touche
pressée, la souris qui bouge, un formulaire envoyé… On demande au navigateur :
« <em>quand</em> tel événement arrive sur tel élément, <em>exécute</em> cette fonction ».
C'est le rôle de <code>addEventListener</code> (« ajouter un écouteur »).
</p>
<div class="bac">
<div class="barre"><span>evenements.js</span>
<div class="boutons"><button class="reinit" type="button">↺</button><button class="executer" type="button">▶ Exécuter</button></div></div>
<textarea aria-label="Éditeur de code">
// Exécute ce code, PUIS clique sur les éléments de la zone blanche ↓
const bouton = scene.querySelector("#compteur");
const champ = scene.querySelector("#champ");
const apercu = scene.querySelector("#apercu");
const carre = scene.querySelector("#carre");
// --- Un compteur de clics ---
let clics = 0; // l'ÉTAT : une variable qui garde la mémoire entre deux clics
bouton.addEventListener("click", () => {
clics++;
bouton.textContent = `Cliqué ${clics} fois`;
console.log("clic !", clics);
});
// --- Réagir à la saisie ---
// "input" se déclenche à chaque caractère tapé
champ.addEventListener("input", (evenement) => {
// evenement.target = l'élément qui a déclenché l'événement
const texte = evenement.target.value;
apercu.textContent = texte.toUpperCase() || "(vide)";
});
// --- Survol de la souris ---
carre.addEventListener("mouseenter", () => carre.style.transform = "rotate(45deg) scale(1.2)");
carre.addEventListener("mouseleave", () => carre.style.transform = "");
// --- Position de la souris ---
carre.addEventListener("mousemove", (e) => {
// offsetX / offsetY : position dans l'élément, en pixels
carre.textContent = `${e.offsetX},${e.offsetY}`;
});
console.log("Écouteurs installés. À toi de jouer !");
</textarea>
<div class="sortie" aria-live="polite"></div>
<div class="scene">
<p><button id="compteur" type="button">Clique-moi</button></p>
<p><input id="champ" placeholder="Tape quelque chose…" aria-label="Champ de test"> → <strong id="apercu">(vide)</strong></p>
<div id="carre" style="width:80px;height:80px;background:#3b7dd8;color:#fff;display:grid;place-items:center;font-size:12px;transition:transform .3s;border-radius:8px">survole</div>
</div>
</div>
<h3>Les événements les plus utiles</h3>
<table>
<tr><th>Événement</th><th>Se déclenche quand…</th></tr>
<tr><td><code>click</code></td><td>on clique</td></tr>
<tr><td><code>input</code></td><td>la valeur d'un champ change (à chaque frappe)</td></tr>
<tr><td><code>submit</code></td><td>un formulaire est envoyé (penser à <code>e.preventDefault()</code>)</td></tr>
<tr><td><code>keydown</code></td><td>une touche est enfoncée (<code>e.key</code> dit laquelle)</td></tr>
<tr><td><code>mouseenter</code> / <code>mouseleave</code></td><td>la souris entre / sort</td></tr>
<tr><td><code>scroll</code></td><td>on fait défiler</td></tr>
<tr><td><code>DOMContentLoaded</code></td><td>le HTML est entièrement chargé</td></tr>
</table>
</section>
<!-- ======================================================== -->
<section class="chapitre" id="ch12">
<h2><span class="num">12</span>L'asynchrone : gérer le temps qui passe</h2>
<p>
Jusqu'ici, tout s'exécutait instantanément, dans l'ordre. Mais certaines actions
<strong>prennent du temps</strong> : attendre 2 secondes, télécharger des données
sur internet… JavaScript ne bloque pas la page en attendant : il <strong>continue</strong>
et revient plus tard quand le résultat est prêt. C'est l'<strong>asynchrone</strong>.
</p>
<div class="bac">
<div class="barre"><span>timers.js</span>
<div class="boutons"><button class="reinit" type="button">↺</button><button class="executer" type="button">▶ Exécuter</button></div></div>
<textarea aria-label="Éditeur de code">
console.log("1. Début");
// setTimeout(fonction, délai en millisecondes) : exécute la fonction PLUS TARD
setTimeout(() => {
console.log("3. …1 seconde plus tard");
}, 1000);
console.log("2. Fin du code… mais ce n'est pas fini !");
// Remarque l'ordre d'affichage : 1, 2, puis 3.
// JS n'attend pas le setTimeout : il programme la fonction et continue.
// setInterval : répète toutes les X ms. clearInterval l'arrête.
let n = 0;
const minuterie = setInterval(() => {
n++;
console.log("tic", n);
if (n === 3) clearInterval(minuterie);
}, 500);
</textarea>
<div class="sortie" aria-live="polite"></div>
</div>
<h3>Les promesses et async / await</h3>
<p>
Une <strong>Promise</strong> (promesse) est un objet qui représente un résultat
<em>futur</em> : « je n'ai pas encore la réponse, mais je te promets de te la donner
(ou de te dire que ça a échoué) ». Le mot-clé <code>await</code> permet
<strong>d'attendre</strong> une promesse, dans une fonction marquée <code>async</code>.
</p>
<div class="bac">
<div class="barre"><span>async-await.js</span>
<div class="boutons"><button class="reinit" type="button">↺</button><button class="executer" type="button">▶ Exécuter</button></div></div>
<textarea aria-label="Éditeur de code">
// Une fonction qui renvoie une promesse résolue après "ms" millisecondes
function attendre(ms) {
return new Promise((resolve) => setTimeout(resolve, ms));
}
// Simule une commande au restaurant qui peut échouer
function commander(plat) {
return new Promise((resolve, reject) => {
setTimeout(() => {
if (plat === "licorne") {
reject(new Error("Plat introuvable 🦄")); // échec
} else {
resolve(`🍽 ${plat} servi !`); // succès
}
}, 800);
});
}
// async : cette fonction peut utiliser await
async function repas() {
console.log("On s'installe…");
await attendre(500); // ⏸ on attend ici (sans bloquer la page !)
console.log("On commande.");
const plat = await commander("pizza"); // await "déballe" la promesse
console.log(plat);
// try / catch pour gérer l'échec d'une promesse
try {
const autre = await commander("licorne");
console.log(autre);
} catch (erreur) {
console.warn("Problème :", erreur.message);
}
console.log("L'addition, s'il vous plaît.");
}
repas();
</textarea>
<div class="sortie" aria-live="polite"></div>
</div>
<h3>fetch : récupérer des données sur internet</h3>
<p>
<code>fetch(url)</code> envoie une requête à un serveur et renvoie une promesse.
On récupère le plus souvent du <strong>JSON</strong> (chapitre 9).
Ici, on interroge une API de test gratuite (connexion internet nécessaire).
</p>
<div class="bac">
<div class="barre"><span>fetch.js</span>
<div class="boutons"><button class="reinit" type="button">↺</button><button class="executer" type="button">▶ Exécuter</button></div></div>
<textarea aria-label="Éditeur de code">
const liste = scene.querySelector("ul");
liste.innerHTML = "<li>Chargement…</li>";
try {
// 1. On envoie la requête et on ATTEND la réponse du serveur
const reponse = await fetch("https://jsonplaceholder.typicode.com/users");
// 2. On vérifie que tout s'est bien passé (code HTTP 200-299)
if (!reponse.ok) throw new Error("Erreur HTTP " + reponse.status);
// 3. On transforme le corps de la réponse (texte JSON) en vrais objets JS
const utilisateurs = await reponse.json();
console.log(`${utilisateurs.length} utilisateurs reçus`);
console.log("Le premier :", utilisateurs[0].name, "-", utilisateurs[0].email);
// 4. On les affiche dans la page
liste.innerHTML = ""; // on vide
for (const u of utilisateurs.slice(0, 5)) { // les 5 premiers seulement
const li = document.createElement("li");
li.textContent = `${u.name} (${u.address.city})`;
liste.append(li);
}
} catch (erreur) {
// Pas de connexion, serveur en panne…
liste.innerHTML = "<li>Impossible de charger les données.</li>";
console.error(erreur.message);
}
</textarea>
<div class="sortie" aria-live="polite"></div>
<div class="scene"><ul><li>(rien encore)</li></ul></div>
</div>
</section>
<!-- ======================================================== -->
<section class="chapitre" id="ch13">
<h2><span class="num">13</span>Les classes : des moules à objets</h2>
<p>
Quand on doit créer beaucoup d'objets du même genre (des ennemis dans un jeu, des
produits dans une boutique…), on écrit un <strong>moule</strong> : une
<strong>classe</strong>. Chaque objet fabriqué avec est une <strong>instance</strong>.
C'est la base de la <em>programmation orientée objet</em>.
</p>
<div class="bac">
<div class="barre"><span>classes.js</span>
<div class="boutons"><button class="reinit" type="button">↺</button><button class="executer" type="button">▶ Exécuter</button></div></div>
<textarea aria-label="Éditeur de code">
class Animal {
// constructor est appelé automatiquement à chaque "new Animal(...)"
constructor(nom, cri) {
this.nom = nom; // "this" = l'objet en cours de fabrication
this.cri = cri;
this.energie = 10;
}
// une méthode, partagée par toutes les instances
parler() {
console.log(`${this.nom} fait « ${this.cri} »`);
}
manger(quantite = 1) {
this.energie += quantite;
return this; // renvoyer "this" permet d'enchaîner : a.manger().manger()
}
}
// "new" fabrique une instance à partir de la classe
const chat = new Animal("Minou", "miaou");
const vache = new Animal("Marguerite", "meuh");
chat.parler();
vache.parler();
chat.manger(2).manger(3);
console.log(chat.nom, "a", chat.energie, "d'énergie");
// --- HÉRITAGE : une classe qui étend une autre ---
class Chien extends Animal {
constructor(nom) {
super(nom, "wouf"); // super(...) appelle le constructeur du PARENT
this.tours = [];
}
apprendre(tour) {
this.tours.push(tour);
console.log(`${this.nom} sait maintenant : ${this.tours.join(", ")}`);
}
// On peut REDÉFINIR une méthode du parent
parler() {
super.parler(); // on garde le comportement du parent…
console.log("(et remue la queue)"); // …et on en ajoute
}
}
const rex = new Chien("Rex");
rex.parler();
rex.apprendre("assis");
rex.apprendre("couché");
console.log(rex instanceof Chien, rex instanceof Animal); // true true
console.log(rex);
</textarea>
<div class="sortie" aria-live="polite"></div>
</div>
</section>
<!-- ======================================================== -->
<section class="chapitre" id="ch14">
<h2><span class="num">14</span>Mini-projet : le jeu du nombre mystère</h2>
<p>
On rassemble <strong>tout</strong> : variables, conditions, fonctions, DOM, événements.
L'ordinateur choisit un nombre entre 1 et 100 ; le joueur doit le deviner en un minimum
d'essais. Exécute, joue, puis lis le code et améliore-le !
</p>
<div class="bac">
<div class="barre"><span>jeu.js</span>
<div class="boutons"><button class="reinit" type="button">↺</button><button class="executer" type="button">▶ Exécuter</button></div></div>
<textarea aria-label="Éditeur de code">
// ====== 1. LES ÉLÉMENTS DE LA PAGE ======
const formulaire = scene.querySelector("form");
const champ = scene.querySelector("input");
const message = scene.querySelector(".message");
const historique = scene.querySelector(".historique");
const rejouer = scene.querySelector(".rejouer");
// ====== 2. L'ÉTAT DU JEU ======
// Tout ce dont le jeu doit "se souvenir" pendant la partie
const MAX = 100; // constante en MAJUSCULES : convention pour un réglage
let mystere; // le nombre à trouver
let essais; // nombre de tentatives
let termine; // la partie est-elle finie ?
// ====== 3. LES FONCTIONS ======
// Renvoie un entier aléatoire entre 1 et max (inclus)
function nombreAleatoire(max) {
// Math.random() → nombre à virgule entre 0 (inclus) et 1 (exclu)
// × max → entre 0 et max ; Math.floor arrondit vers le bas ; +1 → de 1 à max
return Math.floor(Math.random() * max) + 1;
}
function afficher(texte, couleur) {
message.textContent = texte;
message.style.color = couleur;
}
function nouvellePartie() {
mystere = nombreAleatoire(MAX);
essais = 0;
termine = false;
historique.textContent = "";
rejouer.hidden = true; // cache le bouton "rejouer"
champ.disabled = false;
champ.value = "";
champ.focus(); // place le curseur dans le champ
afficher(`J'ai choisi un nombre entre 1 et ${MAX}. À toi !`, "inherit");
console.log("(triche) le nombre est", mystere);
}
function verifier(proposition) {
// Garde-fous : on refuse les saisies invalides
if (Number.isNaN(proposition) || proposition < 1 || proposition > MAX) {
afficher(`Entre un nombre entre 1 et ${MAX} !`, "#d64545");
return; // on sort de la fonction tout de suite
}
essais++;
historique.textContent += proposition + " ";
if (proposition === mystere) {
afficher(`🎉 Bravo ! Trouvé en ${essais} essai${essais > 1 ? "s" : ""}.`, "#2f9e5b");
termine = true;
champ.disabled = true;
rejouer.hidden = false;
} else if (proposition < mystere) {
afficher("C'est plus ⬆", "#d4a017");
} else {
afficher("C'est moins ⬇", "#d4a017");
}
}
// ====== 4. LES ÉVÉNEMENTS ======
formulaire.addEventListener("submit", (e) => {
e.preventDefault(); // empêche le rechargement de la page (comportement par défaut d'un form)
if (termine) return;
verifier(Number(champ.value)); // ⚠ value est un TEXTE : on convertit !
champ.value = "";
champ.focus();
});
rejouer.addEventListener("click", nouvellePartie); // on passe la fonction, SANS ()
// ====== 5. LANCEMENT ======
nouvellePartie();
/* 💪 IDÉES D'AMÉLIORATION :
- Limiter à 7 essais, puis "Perdu ! C'était X"
- Garder le meilleur score (une variable en dehors de nouvellePartie)
- Dire "Tu chauffes 🔥" si on est à moins de 5 du nombre
- Ajouter un choix de difficulté (MAX = 10, 100 ou 1000)
*/
</textarea>
<div class="sortie" aria-live="polite"></div>
<div class="scene">
<form>
<label>Ta proposition : <input type="number" min="1" max="100" style="width:90px"></label>
<button type="submit">Valider</button>
<button type="button" class="rejouer" hidden>Rejouer</button>
</form>
<p class="message" style="font-weight:600">Clique sur « Exécuter » pour lancer le jeu.</p>
<p>Essais : <span class="historique"></span></p>
</div>
</div>
</section>
<!-- ======================================================== -->
<section class="chapitre" id="ch15">
<h2><span class="num">15</span>Et après ?</h2>
<h3>Récapitulatif</h3>
<table>
<tr><th>Notion</th><th>À retenir</th></tr>
<tr><td>Variables</td><td><code>const</code> par défaut, <code>let</code> si ça change</td></tr>
<tr><td>Comparaison</td><td>Toujours <code>===</code> et <code>!==</code></td></tr>
<tr><td>Fonctions</td><td>Petites, un seul rôle, un nom qui dit ce qu'elles font</td></tr>
<tr><td>Tableaux</td><td><code>map</code>, <code>filter</code>, <code>find</code>, <code>reduce</code></td></tr>
<tr><td>DOM</td><td><code>querySelector</code>, <code>textContent</code>, <code>classList</code></td></tr>
<tr><td>Événements</td><td><code>addEventListener("click", fonction)</code></td></tr>
<tr><td>Asynchrone</td><td><code>async</code> / <code>await</code> + <code>try</code> / <code>catch</code></td></tr>
</table>
<h3>Comment progresser</h3>
<ul>
<li><strong>Lis les erreurs</strong> : elles disent presque toujours où et pourquoi.</li>
<li><strong><code>console.log</code> partout</strong> quand tu ne comprends pas ce qui se passe.</li>
<li><strong>Découpe</strong> : un gros problème = plein de petits problèmes faciles.</li>
<li><strong>Copie moins, tape plus</strong> : écrire le code soi-même ancre la mémoire.</li>
<li><strong>Relis <code>script.js</code></strong> de cette page : tu sais maintenant tout lire !</li>
</ul>
<h3>Ressources</h3>
<ul>
<li><a href="https://developer.mozilla.org/fr/docs/Learn/JavaScript">MDN Web Docs</a> — la référence, en français</li>
<li><a href="https://fr.javascript.info/">javascript.info</a> — tutoriel complet et clair</li>
<li><a href="https://p5js.org/">p5.js</a> — dessiner et animer avec JS, idéal en école d'art</li>
<li><a href="https://codepen.io/">CodePen</a> — tester HTML/CSS/JS en ligne et partager</li>
</ul>
<div class="exercice">
<strong>Défi final</strong> — Crée ta propre page (un nouveau dossier avec
<code>index.html</code>, <code>style.css</code>, <code>script.js</code>) : une liste de
tâches où l'on peut ajouter une tâche via un champ, la cocher (classe CSS « faite »)
et la supprimer. Tout ce qu'il faut est dans les chapitres 8, 10 et 11.
</div>
</section>
</main>
</div>
</body>
</html>