📝 Formation JavaScript Complète - De Zéro à Héros
Cette formation vous apprendra JavaScript de manière progressive et approfondie.
Chaque concept est expliqué avec le pourquoi, le comment
et des exemples concrets que vous pouvez tester immédiatement.
1. Qu'est-ce que JavaScript et pourquoi l'apprendre ?
Histoire et contexte
JavaScript a été créé en 1995 par Brendan Eich en seulement 10 jours pour le navigateur Netscape.
L'objectif était simple : permettre aux pages web d'être interactives au lieu d'être statiques.
Pourquoi JavaScript est-il incontournable aujourd'hui ?
- Côté client : Seul langage natif du navigateur pour l'interactivité
- Côté serveur : Node.js permet d'utiliser JS partout
- Applications mobiles : React Native, Ionic
- Applications desktop : Electron (VS Code, Discord)
- IoT et embarqué : microcontrôleurs supportent JS
💡 Conseil pratique : Ouvrez la console de votre navigateur (F12 → Console)
pour tester tous les exemples de cette formation en temps réel.
Premier contact
Voici votre premier programme JavaScript. Copiez cette ligne dans la console de votre navigateur :
alert("Bonjour, je commence à apprendre JavaScript !");
Que s'est-il passé ? JavaScript a exécuté une fonction qui affiche une popup.
C'est votre première interaction avec le langage !
2. Variables et types de données
Pourquoi a-t-on besoin de variables ?
Une variable est comme une boîte étiquetée où on stocke des informations.
Sans variables, impossible de mémoriser des données ou de créer des programmes utiles.
Les trois façons de déclarer une variable
var ancien = "à éviter en 2025"; // Ancienne syntaxe, problématique
let moderne = "peut changer"; // Variable moderne, modifiable
const fixe = "ne peut pas changer"; // Constante, valeur figée
Pourquoi éviter var ?
// Problème avec var : portée (scope) confuse
function exempleProblematique() {
for (var i = 0; i < 3; i++) {
setTimeout(() => console.log(i), 100); // Affiche 3, 3, 3 au lieu de 0, 1, 2
}
}
// Solution avec let : portée correcte
function exempleBon() {
for (let i = 0; i < 3; i++) {
setTimeout(() => console.log(i), 100); // Affiche 0, 1, 2
}
}
Règle pratique : Utilisez toujours const par défaut. Si vous devez modifier la variable, utilisez let.
Types de données primitifs
JavaScript reconnaît automatiquement le type de vos données. Voici les types principaux :
// String (chaîne de caractères)
let nom = "Julien";
let message = 'Bonjour'; // Guillemets simples ou doubles
let template = `Salut ${nom} !`; // Template literals avec backticks
// Number (nombre)
let age = 35; // Entier
let prix = 19.99; // Décimal
let infini = Infinity; // Valeur spéciale
let pasUnNombre = NaN; // "Not a Number"
// Boolean (vrai/faux)
let estConnecte = true;
let estAdmin = false;
// Null et undefined
let vide = null; // Volontairement vide
let x; // Non défini = undefined
console.log(x); // Affiche: undefined
Types de données complexes
// Array (tableau) - liste ordonnée
let competences = ["JavaScript", "HTML", "CSS"];
let nombres = [1, 2, 3, 4, 5];
let mixte = ["texte", 42, true]; // Peut mélanger les types
// Object (objet) - collection de propriétés
let personne = {
prenom: "Julien",
age: 35,
estQA: true,
competences: ["JS", "QA", "DevOps"]
};
// Accès aux propriétés
console.log(personne.prenom); // "Julien"
console.log(personne["age"]); // 35
Vérifier le type d'une variable
console.log(typeof "Hello"); // "string"
console.log(typeof 42); // "number"
console.log(typeof true); // "boolean"
console.log(typeof undefined); // "undefined"
console.log(typeof null); // "object" (c'est un bug historique !)
console.log(typeof [1,2,3]); // "object"
console.log(typeof {nom: "Test"}); // "object"
3. Opérateurs : calculer et comparer
Opérateurs arithmétiques
let a = 10;
let b = 3;
console.log(a + b); // 13 (addition)
console.log(a - b); // 7 (soustraction)
console.log(a * b); // 30 (multiplication)
console.log(a / b); // 3.333... (division)
console.log(a % b); // 1 (reste de la division = modulo)
console.log(a ** b); // 1000 (puissance: 10^3)
// Incrémentation/décrémentation
let compteur = 5;
compteur++; // compteur = 6 (ajoute 1 après)
++compteur; // compteur = 7 (ajoute 1 avant)
compteur--; // compteur = 6 (retire 1 après)
Opérateurs de comparaison
// Égalité stricte vs égalité faible
console.log(5 == "5"); // true (conversion automatique)
console.log(5 === "5"); // false (types différents)
console.log(5 != "6"); // true
console.log(5 !== "5"); // true (types différents)
// Comparaisons
console.log(10 > 5); // true
console.log(10 >= 10); // true
console.log(5 < 3); // false
console.log(5 <= 5); // true
Règle d'or : Utilisez toujours === et !== pour éviter les conversions automatiques surprenantes.
Opérateurs logiques
let estConnecte = true;
let estAdmin = false;
// ET logique (&&) - toutes les conditions doivent être vraies
console.log(estConnecte && estAdmin); // false
// OU logique (||) - au moins une condition doit être vraie
console.log(estConnecte || estAdmin); // true
// NON logique (!) - inverse la valeur
console.log(!estConnecte); // false
console.log(!estAdmin); // true
// Utilisation pratique avec des valeurs par défaut
let nom = undefined;
let nomAffiche = nom || "Utilisateur anonyme"; // "Utilisateur anonyme"
4. Structures de contrôle : prendre des décisions
Conditions avec if/else
Les conditions permettent à votre programme de prendre des décisions basées sur les données.
let age = 20;
if (age >= 18) {
console.log("Vous êtes majeur");
} else {
console.log("Vous êtes mineur");
}
// Conditions multiples
let note = 85;
if (note >= 90) {
console.log("Excellente note !");
} else if (note >= 70) {
console.log("Bonne note");
} else if (note >= 50) {
console.log("Note passable");
} else {
console.log("Note insuffisante");
}
Opérateur ternaire (condition compacte)
let age = 20;
let statut = age >= 18 ? "majeur" : "mineur";
console.log(statut); // "majeur"
// Équivalent en if/else plus verbeux :
let statut2;
if (age >= 18) {
statut2 = "majeur";
} else {
statut2 = "mineur";
}
Switch : choix multiples
Quand vous avez plusieurs valeurs possibles pour une même variable, switch est plus lisible que des if/else en cascade.
let jour = "lundi";
switch (jour) {
case "lundi":
console.log("Début de semaine");
break;
case "mardi":
case "mercredi":
case "jeudi":
console.log("Milieu de semaine");
break;
case "vendredi":
console.log("Bientôt le weekend !");
break;
case "samedi":
case "dimanche":
console.log("Weekend !");
break;
default:
console.log("Jour non reconnu");
}
// IMPORTANT: n'oubliez pas les 'break' sinon ça continue !
5. Boucles : répéter des actions
Boucle for classique
Utilisée quand vous connaissez à l'avance le nombre d'itérations.
// Compter de 0 à 4
for (let i = 0; i < 5; i++) {
console.log("Itération numéro : " + i);
}
// Parcourir un tableau avec les indices
let fruits = ["pomme", "banane", "orange"];
for (let i = 0; i < fruits.length; i++) {
console.log(`Fruit ${i + 1}: ${fruits[i]}`);
}
Boucle for...of (pour les tableaux)
Plus simple et moderne pour parcourir les éléments d'un tableau.
let competences = ["JavaScript", "HTML", "CSS"];
for (let competence of competences) {
console.log("Je maîtrise : " + competence);
}
// Plus lisible que :
for (let i = 0; i < competences.length; i++) {
console.log("Je maîtrise : " + competences[i]);
}
Boucle for...in (pour les objets)
let personne = {
nom: "Julien",
age: 35,
role: "QA Architect"
};
for (let propriete in personne) {
console.log(`${propriete}: ${personne[propriete]}`);
}
// Affiche:
// nom: Julien
// age: 35
// role: QA Architect
Boucle while
Utilisée quand vous ne savez pas à l'avance combien d'itérations seront nécessaires.
let compteur = 0;
while (compteur < 3) {
console.log("Compteur : " + compteur);
compteur++; // IMPORTANT: n'oubliez pas d'incrémenter !
}
// Exemple pratique : attendre une condition
let nombreAleatoire;
let tentatives = 0;
while (nombreAleatoire !== 5) {
nombreAleatoire = Math.floor(Math.random() * 10) + 1; // 1-10
tentatives++;
console.log(`Tentative ${tentatives}: ${nombreAleatoire}`);
}
console.log(`Trouvé 5 en ${tentatives} tentatives !`);
6. Fonctions : organiser et réutiliser le code
Pourquoi utiliser des fonctions ?
Les fonctions permettent de découper votre code en petits blocs réutilisables.
Au lieu d'écrire le même code plusieurs fois, vous l'encapsulez dans une fonction.
Déclaration de fonction classique
function saluer(nom) {
return "Bonjour " + nom + " !";
}
// Utilisation
let message = saluer("Julien");
console.log(message); // "Bonjour Julien !"
// Fonction avec plusieurs paramètres
function calculerAge(anneeNaissance, anneeActuelle) {
return anneeActuelle - anneeNaissance;
}
let age = calculerAge(1988, 2025);
console.log(age); // 37
Fonctions fléchées (arrow functions)
Syntaxe plus moderne et concise, introduite en ES6 (2015).
// Fonction classique
function multiplier(a, b) {
return a * b;
}
// Fonction fléchée équivalente
const multiplier2 = (a, b) => {
return a * b;
};
// Version ultra-compacte (pour une seule expression)
const multiplier3 = (a, b) => a * b;
// Un seul paramètre : pas besoin de parenthèses
const doubler = x => x * 2;
// Aucun paramètre : parenthèses obligatoires
const direBonjour = () => "Bonjour !";
console.log(multiplier3(4, 5)); // 20
console.log(doubler(7)); // 14
console.log(direBonjour()); // "Bonjour !"
Paramètres par défaut
function creerProfil(nom, age = 25, role = "Utilisateur") {
return {
nom: nom,
age: age,
role: role
};
}
console.log(creerProfil("Alice"));
// { nom: "Alice", age: 25, role: "Utilisateur" }
console.log(creerProfil("Bob", 30, "Admin"));
// { nom: "Bob", age: 30, role: "Admin" }
Fonctions de rappel (callbacks)
Une fonction peut prendre une autre fonction en paramètre. C'est très courant en JavaScript.
function traiterDonnees(donnees, callback) {
console.log("Traitement en cours...");
let resultat = donnees.map(x => x * 2);
callback(resultat);
}
function afficherResultat(resultat) {
console.log("Résultat :", resultat);
}
traiterDonnees([1, 2, 3, 4], afficherResultat);
// Traitement en cours...
// Résultat : [2, 4, 6, 8]
// Version avec fonction anonyme
traiterDonnees([5, 6, 7], function(resultat) {
console.log("Nouveau résultat :", resultat);
});
// Version avec fonction fléchée
traiterDonnees([8, 9, 10], (resultat) => {
console.log("Résultat final :", resultat);
});
Closures : la magie des fonctions JavaScript
Une closure permet à une fonction d'accéder aux variables de sa fonction parente,
même après que la fonction parente ait terminé son exécution.
function creerCompteur() {
let count = 0; // Variable privée
return function() {
count++; // Accès à la variable de la fonction parente
return count;
};
}
let compteur1 = creerCompteur();
let compteur2 = creerCompteur();
console.log(compteur1()); // 1
console.log(compteur1()); // 2
console.log(compteur2()); // 1 (compteur indépendant)
console.log(compteur1()); // 3
// Pourquoi c'est utile ? Encapsulation et données privées !
function creerBanque() {
let solde = 100; // Variable privée, inaccessible de l'extérieur
return {
deposer: function(montant) {
solde += montant;
return solde;
},
retirer: function(montant) {
if (montant <= solde) {
solde -= montant;
return solde;
} else {
return "Solde insuffisant";
}
},
consulter: function() {
return solde;
}
};
}
let monCompte = creerBanque();
console.log(monCompte.consulter()); // 100
console.log(monCompte.deposer(50)); // 150
console.log(monCompte.retirer(30)); // 120
// console.log(solde); // Erreur ! solde n'est pas accessible
7. Tableaux : gérer des listes de données
Création et accès aux éléments
// Différentes façons de créer un tableau
let fruits = ["pomme", "banane", "orange"];
let nombres = [1, 2, 3, 4, 5];
let mixte = ["texte", 42, true, null];
let vide = [];
// Accès aux éléments (index commence à 0)
console.log(fruits[0]); // "pomme"
console.log(fruits[1]); // "banane"
console.log(fruits[2]); // "orange"
console.log(fruits[3]); // undefined (n'existe pas)
// Propriétés utiles
console.log(fruits.length); // 3
console.log(fruits[fruits.length - 1]); // "orange" (dernier élément)
Méthodes pour modifier les tableaux
let animaux = ["chat", "chien"];
// Ajouter à la fin
animaux.push("oiseau");
console.log(animaux); // ["chat", "chien", "oiseau"]
// Ajouter au début
animaux.unshift("poisson");
console.log(animaux); // ["poisson", "chat", "chien", "oiseau"]
// Retirer le dernier élément
let dernier = animaux.pop();
console.log(dernier); // "oiseau"
console.log(animaux); // ["poisson", "chat", "chien"]
// Retirer le premier élément
let premier = animaux.shift();
console.log(premier); // "poisson"
console.log(animaux); // ["chat", "chien"]
// Trouver l'index d'un élément
let index = animaux.indexOf("chien");
console.log(index); // 1
// Supprimer des éléments par index
animaux.splice(1, 1); // Supprime 1 élément à partir de l'index 1
console.log(animaux); // ["chat"]
Méthodes fonctionnelles modernes
Ces méthodes ne modifient pas le tableau original mais en retournent un nouveau.
let nombres = [1, 2, 3, 4, 5];
// map() : transformer chaque élément
let doubles = nombres.map(n => n * 2);
console.log(doubles); // [2, 4, 6, 8, 10]
// filter() : garder seulement certains éléments
let pairs = nombres.filter(n => n % 2 === 0);
console.log(pairs); // [2, 4]
// reduce() : réduire à une seule valeur
let somme = nombres.reduce((total, n) => total + n, 0);
console.log(somme); // 15
// find() : trouver le premier élément qui correspond
let premierGrand = nombres.find(n => n > 3);
console.log(premierGrand); // 4
// some() : vérifier si au moins un élément correspond
let aDesGrands = nombres.some(n => n > 10);
console.log(aDesGrands); // false
// every() : vérifier si tous les éléments correspondent
let tousPositifs = nombres.every(n => n > 0);
console.log(tousPositifs); // true
Exemple pratique : gestion d'une liste de tâches
let taches = [
{ id: 1, texte: "Apprendre JavaScript", termine: false },
{ id: 2, texte: "Faire les courses", termine: true },
{ id: 3, texte: "Appeler le médecin", termine: false }
];
// Afficher toutes les tâches non terminées
let tachesRestantes = taches.filter(tache => !tache.termine);
console.log("Tâches restantes :", tachesRestantes);
// Marquer une tâche comme terminée
function terminerTache(id) {
let tache = taches.find(t => t.id === id);
if (tache) {
tache.termine = true;
console.log(`Tâche "${tache.texte}" terminée !`);
}
}
terminerTache(1);
// Compter les tâches terminées
let nombreTerminees = taches.filter(t => t.termine).length;
console.log(`${nombreTerminees} tâches terminées sur ${taches.length}`);
8. Objets : structurer des données complexes
Création et utilisation d'objets
// Objet littéral
let personne = {
prenom: "Julien",
nom: "Dupont",
age: 35,
ville: "Paris",
competences: ["JavaScript", "QA", "DevOps"],
// Méthode (fonction dans un objet)
sePresenter: function() {
return `Je m'appelle ${this.prenom} ${this.nom} et j'ai ${this.age} ans.`;
},
// Méthode avec syntaxe courte (ES6)
direBonjour() {
return `Bonjour, je suis ${this.prenom} !`;
}
};
// Accès aux propriétés
console.log(personne.prenom); // "Julien"
console.log(personne["nom"]); // "Dupont"
// Appel de méthodes
console.log(personne.sePresenter());
console.log(personne.direBonjour());
// Modifier des propriétés
personne.age = 36;
personne["ville"] = "Lyon";
// Ajouter de nouvelles propriétés
personne.email = "julien@example.com";
personne.calculerAnneeNaissance = function() {
return new Date().getFullYear() - this.age;
};
Le mot-clé 'this'
this fait référence à l'objet qui appelle la méthode. C'est crucial pour accéder aux autres propriétés de l'objet.
let voiture = {
marque: "Toyota",
modele: "Corolla",
annee: 2020,
getDescription: function() {
// 'this' fait référence à l'objet voiture
return `${this.marque} ${this.modele} de ${this.annee}`;
},
// Attention avec les fonctions fléchées !
getDescriptionFleche: () => {
// 'this' ne fonctionne pas comme attendu avec les fonctions fléchées
return `${this.marque} ${this.modele} de ${this.annee}`; // undefined undefined undefined
}
};
console.log(voiture.getDescription()); // "Toyota Corolla de 2020"
console.log(voiture.getDescriptionFleche()); // "undefined undefined undefined"
Destructuring : extraire des propriétés facilement
let personne = {
prenom: "Alice",
nom: "Martin",
age: 28,
ville: "Paris"
};
// Ancienne façon
let prenom = personne.prenom;
let nom = personne.nom;
// Destructuring (moderne)
let { prenom, nom, age } = personne;
console.log(prenom, nom, age); // "Alice" "Martin" 28
// Avec renommage
let { prenom: prenomUtilisateur, ville: residence } = personne;
console.log(prenomUtilisateur, residence); // "Alice" "Paris"
// Avec valeurs par défaut
let { prenom, profession = "Non spécifié" } = personne;
console.log(profession); // "Non spécifié"
Classes ES6 : orientation objet moderne
class Personne {
constructor(prenom, nom, age) {
this.prenom = prenom;
this.nom = nom;
this.age = age;
}
sePresenter() {
return `Je suis ${this.prenom} ${this.nom}, ${this.age} ans.`;
}
anniversaire() {
this.age++;
console.log(`Joyeux anniversaire ! Maintenant ${this.age} ans.`);
}
// Getter : propriété calculée
get nomComplet() {
return `${this.prenom} ${this.nom}`;
}
// Setter : contrôler l'assignation
set nouveauAge(age) {
if (age >= 0 && age <= 150) {
this.age = age;
} else {
console.log("Âge invalide !");
}
}
}
// Utilisation
let julien = new Personne("Julien", "Dupont", 35);
console.log(julien.sePresenter());
console.log(julien.nomComplet); // Getter
julien.nouveauAge = 36; // Setter
julien.anniversaire();
// Héritage
class Employe extends Personne {
constructor(prenom, nom, age, poste) {
super(prenom, nom, age); // Appel du constructeur parent
this.poste = poste;
}
sePresenter() {
return super.sePresenter() + ` Je travaille comme ${this.poste}.`;
}
}
let alice = new Employe("Alice", "Martin", 28, "Développeuse");
console.log(alice.sePresenter()); // "Je suis Alice Martin, 28 ans. Je travaille comme Développeuse."
9. Manipulation du DOM : interagir avec la page web
Qu'est-ce que le DOM ?
Le DOM (Document Object Model) est la représentation de votre page HTML sous forme d'arbre d'objets.
JavaScript peut modifier cette structure en temps réel pour créer des pages interactives.
Sélectionner des éléments
// Par ID (le plus spécifique)
let bouton = document.getElementById("monBouton");
// Par classe CSS
let elements = document.getElementsByClassName("maClasse");
let premier = elements[0]; // Retourne une collection, prendre le premier
// Par nom de balise
let paragraphes = document.getElementsByTagName("p");
// Sélecteurs CSS modernes (recommandés)
let bouton2 = document.querySelector("#monBouton"); // Premier élément trouvé
let tousLesBoutons = document.querySelectorAll(".bouton"); // Tous les éléments
// Exemples pratiques
let titre = document.querySelector("h1");
let listeElements = document.querySelectorAll("li");
let premierInput = document.querySelector("input[type='text']");
Modifier le contenu
// HTML de départ
// <p id="message">Texte original</p>
// <div id="contenu"><span>Contenu HTML</span></div>
let message = document.getElementById("message");
// Modifier le texte (sécurisé)
message.textContent = "Nouveau texte";
// Modifier le HTML (attention aux failles XSS !)
let contenu = document.getElementById("contenu");
contenu.innerHTML = "<strong>Texte en gras</strong>";
// Modifier les attributs
let image = document.querySelector("img");
image.src = "nouvelle-image.jpg";
image.alt = "Description de la nouvelle image";
// Modifier les classes CSS
let element = document.querySelector(".boite");
element.classList.add("nouvelle-classe");
element.classList.remove("ancienne-classe");
element.classList.toggle("active"); // Ajoute si absent, retire si présent
// Modifier les styles directement
element.style.color = "red";
element.style.backgroundColor = "yellow";
element.style.fontSize = "20px";
Créer et supprimer des éléments
// Créer un nouvel élément
let nouveauParagraphe = document.createElement("p");
nouveauParagraphe.textContent = "Je suis un nouveau paragraphe";
nouveauParagraphe.classList.add("nouveau");
// L'ajouter à la page
let conteneur = document.querySelector(".conteneur");
conteneur.appendChild(nouveauParagraphe);
// Insérer à une position spécifique
let premierEnfant = conteneur.firstElementChild;
conteneur.insertBefore(nouveauParagraphe, premierEnfant);
// Supprimer un élément
let elementASupprimer = document.querySelector(".a-supprimer");
elementASupprimer.remove(); // Méthode moderne
// Ou avec l'ancienne méthode
// elementASupprimer.parentNode.removeChild(elementASupprimer);
// Exemple pratique : créer une liste dynamique
function ajouterElement(texte) {
let liste = document.getElementById("maListe");
let nouvelItem = document.createElement("li");
nouvelItem.textContent = texte;
// Ajouter un bouton de suppression
let boutonSuppr = document.createElement("button");
boutonSuppr.textContent = "Supprimer";
boutonSuppr.onclick = function() {
nouvelItem.remove();
};
nouvelItem.appendChild(boutonSuppr);
liste.appendChild(nouvelItem);
}
ajouterElement("Premier élément");
ajouterElement("Deuxième élément");
10. Gestion des événements : réagir aux actions utilisateur
Qu'est-ce qu'un événement ?
Un événement se produit quand l'utilisateur interagit avec la page : clic, saisie clavier,
mouvement de souris, etc. JavaScript peut "écouter" ces événements et exécuter du code en réponse.
Ajouter des écouteurs d'événements
// HTML : <button id="monBouton">Cliquez-moi</button>
let bouton = document.getElementById("monBouton");
// Méthode moderne (recommandée)
bouton.addEventListener("click", function() {
alert("Bouton cliqué !");
});
// Avec fonction fléchée
bouton.addEventListener("click", () => {
console.log("Clic détecté");
});
// Avec fonction nommée (réutilisable)
function gererClic() {
console.log("Fonction de gestion du clic");
}
bouton.addEventListener("click", gererClic);
// Retirer un écouteur
bouton.removeEventListener("click", gererClic);
Événements courants
// Événements de souris
element.addEventListener("click", () => console.log("Clic"));
element.addEventListener("dblclick", () => console.log("Double-clic"));
element.addEventListener("mouseenter", () => console.log("Souris entre"));
element.addEventListener("mouseleave", () => console.log("Souris sort"));
// Événements de clavier
document.addEventListener("keydown", (event) => {
console.log("Touche pressée :", event.key);
if (event.key === "Enter") {
console.log("Entrée pressée !");
}
});
// Événements de formulaire
let input = document.querySelector("input");
input.addEventListener("input", (event) => {
console.log("Valeur saisie :", event.target.value);
});
input.addEventListener("focus", () => console.log("Focus sur l'input"));
input.addEventListener("blur", () => console.log("Focus perdu"));
// Événement de soumission de formulaire
let formulaire = document.querySelector("form");
formulaire.addEventListener("submit", (event) => {
event.preventDefault(); // Empêche l'envoi normal du formulaire
console.log("Formulaire soumis");
});
Objet événement
Chaque événement fournit un objet contenant des informations utiles.
document.addEventListener("click", (event) => {
console.log("Élément cliqué :", event.target);
console.log("Position X :", event.clientX);
console.log("Position Y :", event.clientY);
console.log("Type d'événement :", event.type);
// Empêcher le comportement par défaut
if (event.target.tagName === "A") {
event.preventDefault(); // Empêche le lien de fonctionner
console.log("Clic sur lien intercepté");
}
});
// Événement clavier avec détails
document.addEventListener("keydown", (event) => {
console.log("Touche :", event.key);
console.log("Code :", event.code);
console.log("Ctrl pressé :", event.ctrlKey);
console.log("Alt pressé :", event.altKey);
console.log("Shift pressé :", event.shiftKey);
});
Délégation d'événements
Technique puissante pour gérer les événements sur des éléments qui n'existent pas encore.
// Au lieu d'ajouter un écouteur sur chaque bouton
// On ajoute un seul écouteur sur le conteneur parent
let conteneur = document.getElementById("conteneur");
conteneur.addEventListener("click", (event) => {
if (event.target.classList.contains("bouton-supprimer")) {
// Un bouton de suppression a été cliqué
let element = event.target.parentElement;
element.remove();
} else if (event.target.classList.contains("bouton-modifier")) {
// Un bouton de modification a été cliqué
console.log("Modification demandée");
}
});
// Maintenant, même les boutons ajoutés dynamiquement fonctionneront !
11. Programmation asynchrone : gérer le temps
Pourquoi l'asynchrone ?
JavaScript est mono-thread, mais les opérations comme les requêtes réseau ou les timers
ne doivent pas bloquer l'interface. L'asynchrone permet d'exécuter du code "plus tard"
sans figer la page.
setTimeout et setInterval
// Exécuter une fonction après un délai
setTimeout(() => {
console.log("Exécuté après 2 secondes");
}, 2000);
// Fonction avec paramètres
function afficherMessage(message, auteur) {
console.log(`${message} - ${auteur}`);
}
setTimeout(afficherMessage, 1000, "Bonjour", "JavaScript");
// Répéter une fonction à intervalles réguliers
let compteur = 0;
let intervalle = setInterval(() => {
compteur++;
console.log(`Compteur : ${compteur}`);
if (compteur >= 5) {
clearInterval(intervalle); // Arrêter la répétition
console.log("Terminé !");
}
}, 1000);
// Annuler un timeout
let timeout = setTimeout(() => {
console.log("Ceci ne s'exécutera pas");
}, 5000);
clearTimeout(timeout); // Annule le timeout
Promises : gérer l'asynchrone proprement
Les Promises représentent une valeur qui sera disponible dans le futur.
Elles permettent d'éviter le "callback hell".
// Créer une Promise
function attendre(duree) {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(`Terminé après ${duree}ms`);
}, duree);
});
}
// Utiliser une Promise
attendre(2000)
.then(resultat => {
console.log(resultat); // "Terminé après 2000ms"
return attendre(1000); // Chaîner une autre Promise
})
.then(resultat => {
console.log(resultat); // "Terminé après 1000ms"
})
.catch(erreur => {
console.error("Erreur :", erreur);
});
// Promise qui peut échouer
function lancerDe() {
return new Promise((resolve, reject) => {
let resultat = Math.floor(Math.random() * 6) + 1;
if (resultat >= 4) {
resolve(`Gagné ! Résultat : ${resultat}`);
} else {
reject(`Perdu ! Résultat : ${resultat}`);
}
});
}
lancerDe()
.then(message => console.log("Succès :", message))
.catch(erreur => console.log("Échec :", erreur));
async/await : syntaxe moderne
async/await rend le code asynchrone plus lisible, comme s'il était synchrone.
// Fonction asynchrone
async function exempleAsync() {
try {
console.log("Début");
let resultat1 = await attendre(1000);
console.log(resultat1);
let resultat2 = await attendre(500);
console.log(resultat2);
console.log("Fin");
} catch (erreur) {
console.error("Erreur attrapée :", erreur);
}
}
exempleAsync();
// Exemple pratique : requête API
async function obtenirUtilisateur(id) {
try {
let response = await fetch(`https://jsonplaceholder.typicode.com/users/${id}`);
if (!response.ok) {
throw new Error(`Erreur HTTP : ${response.status}`);
}
let utilisateur = await response.json();
console.log("Utilisateur :", utilisateur.name);
return utilisateur;
} catch (erreur) {
console.error("Impossible de récupérer l'utilisateur :", erreur);
}
}
obtenirUtilisateur(1);
// Exécuter plusieurs Promises en parallèle
async function exempleParallele() {
try {
let [user1, user2, user3] = await Promise.all([
obtenirUtilisateur(1),
obtenirUtilisateur(2),
obtenirUtilisateur(3)
]);
console.log("Tous les utilisateurs récupérés !");
} catch (erreur) {
console.error("Au moins une requête a échoué :", erreur);
}
}
12. Exercices pratiques complets
Exercice 1 : Calculatrice interactive
<!-- HTML -->
<div class="calculatrice">
<input type="text" id="affichage" readonly>
<div class="boutons">
<button onclick="effacer()">C</button>
<button onclick="ajouterChiffre('/')">÷</button>
<button onclick="ajouterChiffre('*')">×</button>
<button onclick="supprimerDernier()">←</button>
<button onclick="ajouterChiffre('7')">7</button>
<button onclick="ajouterChiffre('8')">8</button>
<button onclick="ajouterChiffre('9')">9</button>
<button onclick="ajouterChiffre('-')">-</button>
<button onclick="ajouterChiffre('4')">4</button>
<button onclick="ajouterChiffre('5')">5</button>
<button onclick="ajouterChiffre('6')">6</button>
<button onclick="ajouterChiffre('+')">+</button>
<button onclick="ajouterChiffre('1')">1</button>
<button onclick="ajouterChiffre('2')">2</button>
<button onclick="ajouterChiffre('3')">3</button>
<button onclick="calculer()" rowspan="2">=</button>
<button onclick="ajouterChiffre('0')" colspan="2">0</button>
<button onclick="ajouterChiffre('.')">.</button>
</div>
</div>
// JavaScript pour la calculatrice
let affichage = document.getElementById('affichage');
let calcul = '';
function ajouterChiffre(valeur) {
calcul += valeur;
affichage.value = calcul;
}
function effacer() {
calcul = '';
affichage.value = '';
}
function supprimerDernier() {
calcul = calcul.slice(0, -1);
affichage.value = calcul;
}
function calculer() {
try {
// ATTENTION : eval() est dangereux en production !
// Ici c'est pour l'exemple, en vrai il faut parser proprement
let resultat = eval(calcul);
affichage.value = resultat;
calcul = resultat.toString();
} catch (erreur) {
affichage.value = 'Erreur';
calcul = '';
}
}
// Gestion du clavier
document.addEventListener('keydown', (event) => {
if (event.key >= '0' && event.key <= '9') {
ajouterChiffre(event.key);
} else if (['+', '-', '*', '/'].includes(event.key)) {
ajouterChiffre(event.key);
} else if (event.key === 'Enter' || event.key === '=') {
calculer();
} else if (event.key === 'Escape') {
effacer();
} else if (event.key === 'Backspace') {
supprimerDernier();
}
});
Exercice 2 : Application météo avec API
<!-- HTML -->
<div class="meteo-app">
<h1>Météo App</h1>
<div class="recherche">
<input type="text" id="villeInput" placeholder="Entrez une ville...">
<button id="rechercherBtn">Rechercher</button>
</div>
<div id="loader" class="hidden">Chargement...</div>
<div id="resultat" class="hidden">
<h2 id="nomVille"></h2>
<div id="temperature"></div>
<div id="description"></div>
<div id="details"></div>
</div>
<div id="erreur" class="hidden"></div>
</div>
// JavaScript pour l'app météo
class MeteoApp {
constructor() {
this.apiKey = 'VOTRE_CLE_API'; // Remplacer par votre clé OpenWeatherMap
this.baseUrl = 'https://api.openweathermap.org/data/2.5/weather';
this.villeInput = document.getElementById('villeInput');
this.rechercherBtn = document.getElementById('rechercherBtn');
this.loader = document.getElementById('loader');
this.resultat = document.getElementById('resultat');
this.erreur = document.getElementById('erreur');
this.initEventListeners();
}
initEventListeners() {
this.rechercherBtn.addEventListener('click', () => this.rechercherMeteo());
this.villeInput.addEventListener('keypress', (event) => {
if (event.key === 'Enter') {
this.rechercherMeteo();
}
});
}
async rechercherMeteo() {
let ville = this.villeInput.value.trim();
if (!ville) {
this.afficherErreur('Veuillez entrer le nom d\'une ville');
return;
}
this.afficherLoader();
try {
let url = `${this.baseUrl}?q=${ville}&appid=${this.apiKey}&units=metric&lang=fr`;
let response = await fetch(url);
if (!response.ok) {
throw new Error(`Ville non trouvée (${response.status})`);
}
let donnees = await response.json();
this.afficherResultat(donnees);
} catch (erreur) {
this.afficherErreur(`Erreur : ${erreur.message}`);
}
}
afficherLoader() {
this.cacher([this.resultat, this.erreur]);
this.montrer([this.loader]);
}
afficherResultat(donnees) {
document.getElementById('nomVille').textContent =
`${donnees.name}, ${donnees.sys.country}`;
document.getElementById('temperature').textContent =
`${Math.round(donnees.main.temp)}°C`;
document.getElementById('description').textContent =
donnees.weather[0].description;
document.getElementById('details').innerHTML = `
<p>Ressenti : ${Math.round(donnees.main.feels_like)}°C</p>
<p>Humidité : ${donnees.main.humidity}%</p>
<p>Vent : ${donnees.wind.speed} m/s</p>
`;
this.cacher([this.loader, this.erreur]);
this.montrer([this.resultat]);
}
afficherErreur(message) {
this.erreur.textContent = message;
this.cacher([this.loader, this.resultat]);
this.montrer([this.erreur]);
}
cacher(elements) {
elements.forEach(el => el.classList.add('hidden'));
}
montrer(elements) {
elements.forEach(el => el.classList.remove('hidden'));
}
}
// Initialiser l'application
let app = new MeteoApp();
Exercice 3 : Jeu de mémoire (Memory)
// Jeu de mémoire complet
class JeuMemoire {
constructor() {
this.cartes = ['🐶', '🐱', '🐭', '🐹', '🐰', '🦊', '🐻', '🐼'];
this.plateau = [...this.cartes, ...this.cartes]; // Doubler pour les paires
this.cartesRetournees = [];
this.pairesTrouvees = 0;
this.tentatives = 0;
this.jeuActif = false;
this.initPlateau();
this.melangerCartes();
this.creerInterface();
}
initPlateau() {
this.container = document.getElementById('jeu-memoire') || this.creerContainer();
}
creerContainer() {
let container = document.createElement('div');
container.id = 'jeu-memoire';
container.innerHTML = `
<h2>Jeu de Mémoire</h2>
<div id="stats">
<span>Tentatives : <span id="compteur-tentatives">0</span></span>
<button id="nouveau-jeu">Nouveau Jeu</button>
</div>
<div id="plateau"></div>
`;
document.body.appendChild(container);
return container;
}
melangerCartes() {
for (let i = this.plateau.length - 1; i > 0; i--) {
let j = Math.floor(Math.random() * (i + 1));
[this.plateau[i], this.plateau[j]] = [this.plateau[j], this.plateau[i]];
}
}
creerInterface() {
let plateauEl = document.getElementById('plateau');
plateauEl.innerHTML = '';
plateauEl.style.cssText = `
display: grid;
grid-template-columns: repeat(4, 100px);
gap: 10px;
margin: 20px 0;
`;
this.plateau.forEach((carte, index) => {
let carteEl = document.createElement('div');
carteEl.className = 'carte';
carteEl.dataset.index = index;
carteEl.dataset.valeur = carte;
carteEl.textContent = '?';
carteEl.style.cssText = `
width: 100px;
height: 100px;
background: #3498db;
display: flex;
align-items: center;
justify-content: center;
font-size: 24px;
cursor: pointer;
border-radius: 8px;
transition: transform 0.2s;
`;
carteEl.addEventListener('click', () => this.retournerCarte(carteEl));
plateauEl.appendChild(carteEl);
});
document.getElementById('nouveau-jeu').addEventListener('click', () => {
this.nouveauJeu();
});
this.jeuActif = true;
}
retournerCarte(carteEl) {
if (!this.jeuActif ||
carteEl.classList.contains('retournee') ||
this.cartesRetournees.length >= 2) {
return;
}
carteEl.textContent = carteEl.dataset.valeur;
carteEl.style.background = '#2ecc71';
carteEl.classList.add('retournee');
this.cartesRetournees.push(carteEl);
if (this.cartesRetournees.length === 2) {
this.tentatives++;
document.getElementById('compteur-tentatives').textContent = this.tentatives;
setTimeout(() => this.verifierPaire(), 1000);
}
}
verifierPaire() {
let [carte1, carte2] = this.cartesRetournees;
if (carte1.dataset.valeur === carte2.dataset.valeur) {
// Paire trouvée
carte1.style.background = '#f39c12';
carte2.style.background = '#f39c12';
carte1.classList.add('trouvee');
carte2.classList.add('trouvee');
this.pairesTrouvees++;
if (this.pairesTrouvees === this.cartes.length) {
setTimeout(() => {
alert(`Félicitations ! Jeu terminé en ${this.tentatives} tentatives !`);
}, 500);
this.jeuActif = false;
}
} else {
// Pas de paire
carte1.textContent = '?';
carte2.textContent = '?';
carte1.style.background = '#3498db';
carte2.style.background = '#3498db';
carte1.classList.remove('retournee');
carte2.classList.remove('retournee');
}
this.cartesRetournees = [];
}
nouveauJeu() {
this.pairesTrouvees = 0;
this.tentatives = 0;
this.cartesRetournees = [];
document.getElementById('compteur-tentatives').textContent = '0';
this.melangerCartes();
this.creerInterface();
}
}
// Démarrer le jeu
let jeu = new JeuMemoire();
🎯 Félicitations ! Vous avez maintenant une base solide en JavaScript.
Ces exercices combinent tous les concepts vus : variables, fonctions, objets, DOM,
événements, asynchrone, et classes. Continuez à pratiquer en créant vos propres projets !