JavaScript
Les Bases
Variables, types, fonctions, tableaux, objets, asynchrone et DOM — les fondations solides du JavaScript moderne.
JS — c'est quoi ?
JavaScript est un langage interprété, dynamiquement typé et orienté événements. Il tourne dans le navigateur (côté client) et côté serveur (Node.js). C'est l'unique langage natif du web — HTML structure, CSS stylise, JS fait agir.
<!-- 1. Inline (à éviter sauf cas spéciaux) -->
<button onclick="alert('Clic!')">Clic</button>
<!-- 2. Balise <script> dans la page -->
<script>
console.log('Bonjour');
</script>
<!-- 3. Fichier externe (recommandé) -->
<!-- defer : exécute après le parsing du HTML -->
<script src="app.js" defer></script>
<!-- async : exécute dès le téléchargement -->
<script src="analytics.js" async></script>
// Afficher dans la console du navigateur (F12)
console.log('message simple');
console.log('valeur :', maVariable);
console.warn('avertissement');
console.error('erreur');
console.table([{ nom: 'Alice', age: 25 }]);
console.group('Groupe'); console.groupEnd();
console.time('timer'); console.timeEnd('timer');
// Inspecter un objet
console.dir(document.body);
// Débogage — point d'arrêt dans le code
debugger; // pause l'exécution si DevTools ouvert
// 'use strict' — active le mode strict
// Détecte des erreurs silencieuses, interdit
// les variables non déclarées
'use strict';
// typeof — connaître le type d'une valeur
typeof "bonjour" // "string"
typeof 42 // "number"
typeof true // "boolean"
typeof undefined // "undefined"
typeof null // "object" ← bug historique !
typeof [] // "object" ← utiliser Array.isArray()
typeof function(){} // "function"
Variables — var, let, const
var | let | const | |
|---|---|---|---|
| Portée | Fonction | Bloc { } | Bloc { } |
| Réassignable | ✓ | ✓ | ✗ |
| Redéclarable | ✓ | ✗ | ✗ |
| Hoisting | Oui (undefined) | Oui (TDZ*) | Oui (TDZ*) |
| Global window | Oui | Non | Non |
| Utiliser ? | ❌ Jamais | ✅ Si valeur change | ✅ Par défaut |
*TDZ (Temporal Dead Zone) : let et const sont hoistés mais pas initialisés. Y accéder avant leur déclaration lève une ReferenceError — contrairement à var qui renvoie undefined silencieusement.
// ✅ const par défaut — valeur ne change pas
const PI = 3.14159;
const URL_API = 'https://api.exemple.com';
// ✅ const pour les objets et tableaux
// (la référence est constante, pas le contenu !)
const user = { nom: 'Alice', age: 25 };
user.age = 26; // ✅ OK — modifie le contenu
// user = {} // ✗ Erreur — réassignation interdite
// ✅ let si la valeur change
let compteur = 0;
compteur++; // OK
let message = 'Bonjour';
message = 'Salut'; // OK
// Problème classique de var en boucle :
for (var i = 0; i < 3; i++) {
setTimeout(() => console.log(i), 100);
} // Affiche 3, 3, 3 (pas 0, 1, 2 !)
for (let j = 0; j < 3; j++) {
setTimeout(() => console.log(j), 100);
} // Affiche 0, 1, 2 ✅
Types de données
| Type | Exemples | Particularités |
|---|---|---|
| string | 'bonjour' "texte" `template` |
Immuable. Unicode complet. 3 formes de guillemets. |
| number | 42 3.14 NaN Infinity |
Un seul type numérique (IEEE 754 double). NaN !== NaN ! |
| boolean | true false |
Résultat de comparaisons. |
| null | null |
Absence intentionnelle de valeur. Typeof = "object" (bug). |
| undefined | undefined |
Variable déclarée mais non initialisée. |
| Symbol | Symbol('id') |
Clé unique et immuable. Utile pour éviter les collisions. |
| BigInt | 9007199254740993n |
Entiers > Number.MAX_SAFE_INTEGER. |
| object | {} [] new Date() |
Type référence — passé par référence, pas par valeur. |
// NaN — Not a Number
typeof NaN // "number" (😱)
NaN === NaN // false !
Number.isNaN(NaN) // true ✅
Number.isNaN('texte') // false (≠ isNaN global)
// null vs undefined
null == undefined // true (égalité lâche)
null === undefined // false (égalité stricte)
// Référence vs valeur
const a = { x: 1 };
const b = a; // b pointe sur le même objet
b.x = 99;
console.log(a.x); // 99 ! (même référence)
// Cloner un objet (shallow copy)
const c = { ...a }; // spread
const d = Object.assign({}, a);
// Deep copy :
const e = structuredClone(a); // ES2022 ✅
const f = JSON.parse(JSON.stringify(a)); // vieux
// Conversion explicite
Number('42') // 42
Number('') // 0 ← surprenant
Number(null) // 0
Number(undefined) // NaN
String(42) // "42"
Boolean(0) // false
Opérateurs
// == égalité lâche (avec coercition de type)
0 == '' // true ← dangereux
0 == '0' // true
null == undefined // true
false == 0 // true
// === égalité stricte (sans coercition) ✅
0 === '' // false
42 === 42 // true
'a' === 'a' // true
// Toujours utiliser === sauf null check
if (valeur == null) { } // catch null ET undefined
// Opérateurs logiques
&& // ET — retourne la première valeur falsy
|| // OU — retourne la première valeur truthy
! // NON
?? // Nullish coalescing — retourne droite si null/undefined
// Court-circuit
const nom = user && user.nom; // si user est truthy
const val = input || 'défaut'; // valeur par défaut
const v = data ?? 'défaut'; // null/undefined seulement
// Optional chaining ?. (ES2020)
// Évite "Cannot read property of undefined"
const ville = user?.adresse?.ville;
// Équivalent à :
// user && user.adresse && user.adresse.ville
user?.nom // propriété optionnelle
tableau?.[0] // index optionnel
fonc?.() // appel optionnel
// Nullish assignment ??= (ES2021)
user.prenom ??= 'Inconnu';
// Assigne seulement si null ou undefined
// Logical assignment ||= et &&=
config.debug ||= false;
// config.debug = config.debug || false
// Exponentiation **
2 ** 10 // 1024 (= Math.pow(2, 10))
// Ternaire
const statut = age >= 18 ? 'majeur' : 'mineur';
// Comma — évalue gauche et droite, retourne droite
let x = (1, 2, 3); // x = 3
Coercition & truthy / falsy
JavaScript convertit automatiquement les types dans certains contextes — c'est la coercition de type. Comprendre les valeurs truthy/falsy évite de nombreux bugs.
// Addition + : coercition vers string
"3" + 4 // "34" ← concaténation !
1 + 2 + "3" // "33" ← 1+2=3 puis "3"+"3"
"3" + 1 + 2 // "312" ← "3"+1="31" puis "31"+2
// Autres opérateurs : coercition vers number
"5" - 2 // 3 ← soustraction numérique
"5" * "2" // 10
true + true // 2 ← true = 1
[] + [] // "" ← [].toString() = ""
[] + {} // "[object Object]"
// Bonnes pratiques pour éviter les surprises :
const n = Number(input) || 0; // conversion explicite
if (tableau.length === 0) {} // pas juste if(!tableau)
Conditions
const note = 14;
if (note >= 16) {
console.log('Distinction');
} else if (note >= 10) {
console.log('Réussi');
} else {
console.log('Échec');
}
// switch — comparaison stricte (===)
switch (jour) {
case 'lundi':
case 'mardi': // fall-through intentionnel
console.log('Début de semaine');
break;
case 'vendredi':
console.log('TGIF');
break;
default:
console.log('Milieu de semaine');
}
// Ternaire imbriqué (à éviter si trop long)
const cat = note >= 16 ? 'A'
: note >= 14 ? 'B'
: note >= 10 ? 'C'
: 'F';
// Guard clauses — sortir tôt plutôt qu'imbriquer
// ✗ À éviter :
function traiter(user) {
if (user) {
if (user.actif) {
// traitement...
}
}
}
// ✅ Guard clauses :
function traiter(user) {
if (!user) return;
if (!user.actif) return;
// traitement principal ici — peu imbriqué
}
// Object lookup — remplace un gros switch
const actions = {
'ajouter': () => panier.push(item),
'supprimer': () => panier.pop(),
'vider': () => panier.splice(0),
};
const fn = actions[action];
if (fn) fn(); // appeler si l'action existe
Boucles
// for classique
for (let i = 0; i < 5; i++) {
console.log(i); // 0, 1, 2, 3, 4
}
// for...of — itérer sur les valeurs
const fruits = ['pomme', 'banane', 'cerise'];
for (const fruit of fruits) {
console.log(fruit); // pomme, banane, cerise
}
// Fonctionne aussi sur : string, Map, Set, NodeList
// for...in — itérer sur les clés d'un objet
const personne = { nom: 'Bob', age: 30 };
for (const cle in personne) {
console.log(cle, personne[cle]);
}
// ⚠ Éviter for...in sur les tableaux
// while
let n = 1;
while (n < 100) { n *= 2; }
// break et continue
for (const x of nombres) {
if (x < 0) continue; // sauter les négatifs
if (x > 100) break; // arrêter si > 100
traiter(x);
}
const notes = [12, 15, 8, 18, 10];
// forEach — pour les effets de bord
notes.forEach((n, i) => console.log(i, n));
// map — transformer chaque élément
const doubles = notes.map(n => n * 2);
// [24, 30, 16, 36, 20]
// filter — garder selon condition
const reçus = notes.filter(n => n >= 10);
// [12, 15, 18, 10]
// find — premier élément correspondant
const premiere = notes.find(n => n > 14);
// 15
// reduce — accumuler en une valeur
const somme = notes.reduce((acc, n) => acc + n, 0);
// 63
// some / every
notes.some(n => n >= 18) // true (au moins un)
notes.every(n => n >= 10) // false (pas tous)
// Chaîner les méthodes
const moyenneReçus = notes
.filter(n => n >= 10)
.reduce((a, n, _, arr) => a + n / arr.length, 0);
Fonctions
// 1. Déclaration — hoistée, utilisable avant la def
function saluer(nom) {
return `Bonjour, ${nom} !`;
}
// 2. Expression — non hoistée
const saluer = function(nom) {
return `Bonjour, ${nom} !`;
};
// 3. Arrow function (ES6) — pas de this propre
const saluer = (nom) => `Bonjour, ${nom} !`;
const double = n => n * 2; // 1 paramètre : pas de ()
const objet = () => ({ x: 1 }); // retourner un objet : ({})
// 4. Méthode dans un objet
const calc = {
valeur: 0,
ajouter(n) { this.valeur += n; }, // this = calc
reset: () => { /* this ≠ calc ici ! */ },
};
// Valeurs par défaut
function créer(nom, role = 'utilisateur', actif = true) {
return { nom, role, actif };
}
créer('Alice'); // {nom:'Alice', role:'utilisateur', actif:true}
// Rest parameter — nombre variable d'arguments
function somme(...nombres) {
return nombres.reduce((a, b) => a + b, 0);
}
somme(1, 2, 3, 4); // 10
// Destructuring en paramètres
function afficher({ nom, age, ville = 'Inconnue' }) {
console.log(`${nom}, ${age} ans, ${ville}`);
}
afficher({ nom: 'Bob', age: 30 });
// Fonctions d'ordre supérieur
const multiplier = (x) => (y) => x * y;
const double = multiplier(2);
const triple = multiplier(3);
double(5); // 10
triple(5); // 15
// IIFE — Immediately Invoked Function Expression
(function() {
const prive = 'ne pollue pas le scope global';
})();
Portée (scope) & closures
// Une closure = fonction qui "mémorise"
// les variables de son scope parent,
// même après que celui-ci ait terminé.
function créerCompteur() {
let count = 0; // variable privée !
return {
incrémenter() { count++; },
décrémenter() { count--; },
valeur() { return count; },
};
}
const c = créerCompteur();
c.incrémenter();
c.incrémenter();
c.valeur(); // 2
// count est inaccessible depuis l'extérieur !
// Utilisation pratique — mémorisation
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 fibMemo = memoize(function fib(n) {
return n <= 1 ? n : fibMemo(n-1) + fibMemo(n-2);
});
Tableaux (Array)
const arr = [1, 2, 3];
// Ajouter / supprimer
arr.push(4); // fin → [1,2,3,4]
arr.pop(); // fin → [1,2,3]
arr.unshift(0); // début → [0,1,2,3]
arr.shift(); // début → [1,2,3]
// splice — couteau suisse
arr.splice(1, 1); // supprimer index 1 → [1,3]
arr.splice(1, 0, 99); // insérer 99 à index 1
arr.splice(1, 1, 88); // remplacer index 1 par 88
// Trier
[3, 1, 2].sort(); // [1,2,3] (lexicographique!)
[10, 3, 20].sort((a,b)=>a-b); // [3,10,20] ✅ numérique
arr.reverse(); // inverse en place
arr.fill(0, 1, 3); // remplace [1,3) par 0
// Non-mutantes — retournent un nouveau tableau
[1,2].concat([3,4]) // [1,2,3,4]
arr.slice(1, 3) // sous-tableau [1,3)
arr.toSorted(…) // copie triée (ES2023)
arr.toReversed() // copie inversée (ES2023)
arr.with(1, 99) // copie avec index 1 = 99
arr.flat(2) // aplatir sur 2 niveaux
arr.flatMap(x => [x,x]) // map + flat(1)
// Recherche
arr.includes(5) // true/false
arr.indexOf(5) // index ou -1
arr.findIndex(x => x > 3) // premier index valide
arr.findLast(x => x < 5) // dernier élément (ES2023)
// Info
Array.isArray([]) // true
arr.length // longueur
arr.join(', ') // "1, 2, 3"
// Créer des tableaux
Array.from('abc') // ['a','b','c']
Array.from({length: 5}, (_, i) => i) // [0,1,2,3,4]
[...new Set([1, 2, 1, 3])] // [1,2,3] dédupliqué
Objets
// Littéral d'objet
const user = {
nom: 'Alice',
age: 25,
adresse: { ville: 'Paris', cp: '75001' },
saluer() { return `Je suis ${this.nom}`; },
};
// Accès
user.nom // dot notation
user['nom'] // bracket notation (dynamique)
const cle = 'age';
user[cle] // 25 — utile avec des clés variables
// Ajouter / modifier / supprimer
user.email = 'alice@ex.com'; // ajouter
user.age = 26; // modifier
delete user.adresse; // supprimer
// Vérifier l'existence d'une clé
'nom' in user // true
user.hasOwnProperty('nom') // true (propre, pas hérité)
user.nom !== undefined // moins fiable
const obj = { a: 1, b: 2, c: 3 };
// Itérer
Object.keys(obj) // ['a', 'b', 'c']
Object.values(obj) // [1, 2, 3]
Object.entries(obj) // [['a',1], ['b',2], ['c',3]]
for (const [cle, val] of Object.entries(obj)) {
console.log(cle, val);
}
// Fusionner des objets
const base = { a: 1, b: 2 };
const extras = { b: 99, c: 3 }; // b écrase base.b
const fusionné = { ...base, ...extras }; // {a:1,b:99,c:3}
const f2 = Object.assign({}, base, extras); // idem
// Geler un objet (immuable)
const config = Object.freeze({ version: '1.0' });
config.version = '2.0'; // silencieusement ignoré
// Raccourci propriété (shorthand)
const nom = 'Alice', age = 25;
const user = { nom, age }; // { nom: 'Alice', age: 25 }
// Propriété calculée
const champ = 'email';
const u = { [champ]: 'alice@ex.com' };
Destructuring & spread
// Tableau
const [a, b, c] = [10, 20, 30];
const [x, , z] = [1, 2, 3]; // sauter le 2ème
const [head, ...tail] = [1, 2, 3, 4]; // rest
// Swap sans variable temporaire
let p = 1, q = 2;
[p, q] = [q, p]; // p=2, q=1
// Objet
const { nom, age } = user;
const { nom: prenom, age: annees } = user; // renommer
const { nom, ville = 'Paris' } = user; // valeur défaut
const { adresse: { cp } } = user; // imbriqué
// Rest en objet
const { nom: n, ...reste } = user;
// n = 'Alice', reste = { age:25, email:... }
// Dans les paramètres de fonction
function afficher([a, b], { nom, age = 0 }) { ... }
// Copier et fusionner des tableaux
const a = [1, 2], b = [3, 4];
const c = [...a, ...b]; // [1,2,3,4]
const copie = [...a]; // copie indépendante
const avecZero = [0, ...a]; // [0,1,2]
// Copier et fusionner des objets
const base = { a: 1 };
const maj = { ...base, b: 2 }; // { a:1, b:2 }
// Passer un tableau comme arguments
const nombres = [3, 1, 4, 1, 5];
Math.max(...nombres); // 5
// Convertir itérables en tableaux
[...new Set([1,2,1])] // [1,2] — dédupliquer
[...'abc'] // ['a','b','c']
[...document.querySelectorAll('li')] // NodeList → Array
// Mise à jour immuable (pattern Redux)
const state = { user: { nom: 'Alice', score: 0 } };
const newState = {
...state,
user: { ...state.user, score: state.user.score + 1 }
};
Chaînes & template literals
// Template literals — backtick
const nom = 'Alice', age = 25;
const msg = `${nom} a ${age} ans`;
const multi = `
Ligne 1
Ligne 2
Résultat : ${2 * age}
`;
// Méthodes de String
' bonjour '.trim() // 'bonjour'
'bonjour'.toUpperCase() // 'BONJOUR'
'BONJOUR'.toLowerCase() // 'bonjour'
'bonjour'.includes('jour') // true
'bonjour'.startsWith('bon') // true
'bonjour'.endsWith('jour') // true
'bonjour'.indexOf('j') // 3
'bonjour'.slice(3, 6) // 'jou'
'a,b,c'.split(',') // ['a','b','c']
'ha'.repeat(3) // 'hahaha'
'5'.padStart(3, '0') // '005'
'bon'.padEnd(7, '!') // 'bon!!!!'
'ab-cd'.replaceAll('-', '_') // 'ab_cd'
// Créer une regex
const regex1 = /hello/i; // littéral
const regex2 = new RegExp('hello', 'i'); // dynamique
// Flags : i=case-insensitive, g=global, m=multiline
// Méthodes de String avec regex
'Bonjour'.match(/jour/) // ['jour']
'Bonjour'.test // ← méthode de RegExp
/jour/.test('Bonjour') // true
'bon-jour'.replace(/-/g, '_') // 'bon_jour'
'a1b2c3'.match(/\d+/g) // ['1','2','3']
// Validation email simple
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
emailRegex.test('alice@exemple.com'); // true
// Groupes de capture
const date = '2024-03-15';
const match = date.match(/(\d{4})-(\d{2})-(\d{2})/);
// match[1]='2024', match[2]='03', match[3]='15'
// Named groups (ES2018)
const { groups: { annee, mois } } =
date.match(/(?<annee>\d{4})-(?<mois>\d{2})/);
L'Event Loop
JavaScript est mono-thread — il ne fait qu'une chose à la fois. L'Event Loop permet quand même de gérer des opérations asynchrones (réseau, timers, I/O) sans bloquer le thread.
LIFO (dernier entré, premier sorti)
au navigateur/Node
FIFO (premier entré, premier sorti)
Fonctionnement : quand la Call Stack est vide, l'Event Loop prend le premier callback de la Queue et le met dans la Stack. La Microtask Queue (Promises) a priorité sur la Macrotask Queue (setTimeout, setInterval) — toutes les microtasks sont vidées avant la prochaine macrotask.
Callbacks
// Un callback = fonction passée en argument,
// appelée quand l'opération est terminée
setTimeout(() => {
console.log('Affiché après 1 seconde');
}, 1000);
// Pattern Node.js : error-first callback
fs.readFile('fichier.txt', 'utf8', (err, data) => {
if (err) {
console.error('Erreur :', err);
return;
}
console.log(data);
});
Callback hell : les callbacks imbriqués deviennent vite illisibles. C'est pourquoi les Promises (puis async/await) ont été créées pour aplatir le code asynchrone.
// ✗ Pyramid of doom
connexion(user, (err, session) => {
if (err) { handleError(err); return; }
chargerProfil(session, (err, profil) => {
if (err) { handleError(err); return; }
chargerPréférences(profil, (err, prefs) => {
if (err) { handleError(err); return; }
afficherDashboard(session, profil, prefs);
});
});
});
// ✅ Avec async/await (voir section suivante)
async function chargerDashboard(user) {
const session = await connexion(user);
const profil = await chargerProfil(session);
const prefs = await chargerPréférences(profil);
afficherDashboard(session, profil, prefs);
}
Promises
// Créer une Promise
const p = new Promise((resolve, reject) => {
// opération asynchrone...
if (succès) resolve(résultat);
else reject(new Error('Échec'));
});
// Consommer avec .then().catch().finally()
chargerDonnées()
.then(data => traiter(data))
.then(result => afficher(result))
.catch(err => console.error(err))
.finally(() => masquerChargement());
// États d'une Promise :
// pending → en cours
// fulfilled → résolue avec une valeur
// rejected → rejetée avec une erreur
// settled → fulfilled ou rejected (définitif)
// Promise.resolve / .reject — raccourcis
Promise.resolve(42).then(v => console.log(v));
Promise.reject(new Error('erreur')).catch(console.error);
// Promise.all — attend TOUTES, échoue si 1 échoue
const [users, posts, comments] = await Promise.all([
fetch('/api/users').then(r => r.json()),
fetch('/api/posts').then(r => r.json()),
fetch('/api/comments').then(r => r.json()),
]);
// 3 requêtes en parallèle !
// Promise.allSettled — attend TOUTES, ne fail pas
const résultats = await Promise.allSettled([p1, p2, p3]);
résultats.forEach(r => {
if (r.status === 'fulfilled') console.log(r.value);
else console.error(r.reason);
});
// Promise.race — la première qui se termine gagne
const résultat = await Promise.race([
fetch('/api/data'),
timeout(5000), // Promise qui rejette après 5s
]);
// Promise.any — la première résolue (ES2021)
const data = await Promise.any([
fetchFromServer1(), fetchFromServer2(), fetchFromServer3()
]);
// Prend le plus rapide qui réussit
async / await
// async rend une fonction asynchrone
// Elle retourne TOUJOURS une Promise
async function charger() {
return 42; // Équivalent à Promise.resolve(42)
}
// await suspend la fonction jusqu'à résolution
// Ne peut s'utiliser que dans une fonction async
async function chargerUtilisateur(id) {
try {
const réponse = await fetch(`/api/users/${id}`);
if (!réponse.ok) {
throw new Error(`HTTP ${réponse.status}`);
}
const user = await réponse.json();
return user;
} catch (err) {
console.error('Erreur réseau :', err);
throw err; // re-propager si besoin
} finally {
masquerLoader(); // toujours exécuté
}
}
// Arrow function async
const getData = async (url) => {
const res = await fetch(url);
return res.json();
};
// ✗ Séquentiel inutile (perd l'avantage async)
const users = await fetchUsers(); // 500ms
const posts = await fetchPosts(); // 300ms
// Total : 800ms
// ✅ Parallèle avec Promise.all
const [users, posts] = await Promise.all([
fetchUsers(), fetchPosts()
]);
// Total : ~500ms
// ✗ await dans forEach — ne fonctionne PAS
items.forEach(async (item) => {
await sauvegarder(item); // ignoré !
});
// ✅ for...of pour await séquentiel
for (const item of items) {
await sauvegarder(item);
}
// ✅ Promise.all pour parallèle
await Promise.all(items.map(sauvegarder));
// Top-level await (modules ES2022)
const config = await fetch('/config.json').then(r => r.json());
// ← Directement au niveau du module, sans async fn
Manipulation du DOM
// Sélectionner
document.querySelector('#btn') // 1 élément
document.querySelectorAll('.carte') // NodeList
document.getElementById('titre') // par id
document.getElementsByClassName('x') // HTMLCollection (live)
// Navigation dans le DOM
el.parentElement
el.children // éléments enfants
el.firstElementChild
el.lastElementChild
el.nextElementSibling
el.previousElementSibling
el.closest('.parent') // ancêtre le plus proche
// Modifier le contenu
el.textContent = 'Nouveau texte'; // sûr
el.innerHTML = '<b>Gras</b>'; // XSS si user input !
// Attributs
el.getAttribute('href')
el.setAttribute('href', 'https://...')
el.removeAttribute('disabled')
el.hasAttribute('required')
el.dataset.userId // <el data-user-id="42">
// Classes CSS
el.classList.add('actif')
el.classList.remove('actif')
el.classList.toggle('ouvert')
el.classList.contains('visible')
el.classList.replace('old', 'new')
// Styles inline
el.style.color = 'red';
el.style.display = 'none';
el.style.setProperty('--color', 'blue');
// Créer et insérer des éléments
const li = document.createElement('li');
li.textContent = 'Nouvel élément';
li.className = 'item';
ul.appendChild(li);
ul.prepend(li);
ul.insertBefore(li, autreEl);
el.insertAdjacentHTML('beforeend', '<li>...</li>');
// Supprimer
el.remove();
parent.removeChild(el);
// Cloner
const copie = el.cloneNode(true); // true = deep clone
// Mesures
el.getBoundingClientRect() // position + dimensions
el.offsetWidth / offsetHeight
el.scrollTop / scrollLeft
Événements
// Ajouter un listener
btn.addEventListener('click', (e) => {
console.log('Cliqué !', e.target);
});
// Supprimer (nécessite une référence nommée)
const handler = (e) => console.log(e);
btn.addEventListener('click', handler);
btn.removeEventListener('click', handler);
// L'objet Event
e.target // élément cliqué
e.currentTarget // élément sur lequel le listener est
e.preventDefault() // empêcher comportement par défaut
e.stopPropagation() // arrêter la propagation
// Clavier
input.addEventListener('keydown', (e) => {
if (e.key === 'Enter') soumettre();
if (e.key === 'Escape') fermer();
e.ctrlKey // Ctrl enfoncé
e.shiftKey // Shift enfoncé
});
// Délégation d'événements
// Au lieu d'ajouter un listener sur chaque li :
ul.addEventListener('click', (e) => {
const li = e.target.closest('li');
if (!li) return;
li.classList.toggle('selectionné');
});
// Souris
click, dblclick, mouseenter, mouseleave
mouseover, mouseout, mousemove
mousedown, mouseup, contextmenu
// Clavier
keydown, keyup, keypress (déprécié)
// Formulaire
submit, change, input, focus, blur, reset
// Document / Fenêtre
DOMContentLoaded // HTML parsé (sans attendre images)
load // tout chargé (images comprises)
resize, scroll
// Touch (mobile)
touchstart, touchmove, touchend
// Attendre que le DOM soit prêt
document.addEventListener('DOMContentLoaded', () => {
// Code JS ici — DOM disponible
});
// Debounce — limiter la fréquence d'appel
function debounce(fn, delay) {
let timer;
return (...args) => {
clearTimeout(timer);
timer = setTimeout(() => fn(...args), delay);
};
}
window.addEventListener('resize', debounce(handler, 200));
Fetch API
// GET — récupérer des données
async function getUsers() {
const res = await fetch('/api/users');
if (!res.ok) throw new Error(res.status);
return res.json();
}
// POST — envoyer des données JSON
async function createUser(userData) {
const res = await fetch('/api/users', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(userData),
});
return res.json();
}
// PUT / PATCH / DELETE
await fetch(`/api/users/${id}`, {
method: 'DELETE',
headers: { 'Authorization': `Bearer ${token}` },
});
// Fonction utilitaire avec gestion d'erreurs
async function api(endpoint, options = {}) {
const defaults = {
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${getToken()}`,
},
};
const config = {
...defaults,
...options,
headers: { ...defaults.headers, ...options.headers },
};
const res = await fetch(`/api${endpoint}`, config);
if (!res.ok) {
const errData = await res.json().catch(() => ({}));
throw new Error(errData.message || `HTTP ${res.status}`);
}
if (res.status === 204) return null; // No Content
return res.json();
}
// Utilisation propre
const user = await api('/users/42');
const created = await api('/users', {
method: 'POST',
body: JSON.stringify({ nom: 'Alice' }),
});
Cheat sheet
Variables & types
| const | Par défaut — référence constante |
| let | Si la valeur change |
| var | Jamais — scope fonction, hoisting |
| === | Toujours (jamais ==) |
| typeof null | "object" ← bug historique |
| ?? vs || | ?? : null/undef seulement |
Tableaux — méthodes clés
| map(fn) | Transformer → nouveau tableau |
| filter(fn) | Filtrer → sous-tableau |
| reduce(fn, init) | Accumuler → valeur unique |
| find(fn) | Premier élément trouvé |
| some/every | Au moins un / tous |
| flat/flatMap | Aplatir / map + flat |
Asynchrone
| async fn | Retourne une Promise |
| await | Suspend jusqu'à résolution |
| try/catch | Gérer les erreurs async |
| Promise.all | Tout en parallèle |
| Promise.allSettled | Tout, même si erreur |
| await en forEach | Ne fonctionne PAS |
DOM & événements
| querySelector | 1er élément CSS selector |
| querySelectorAll | Tous les éléments |
| addEventListener | Attacher un événement |
| e.target | Élément déclencheur |
| e.preventDefault() | Annuler défaut navigateur |
| Délégation | Listener sur parent |