JavaScript — Bases
JavaScript est souvent décrit comme le "cerveau" des pages web. C’est le langage qui permet de transformer un document statique en une expérience interactive et dynamique.
Voici un tour d'horizon pour comprendre d'où il vient et ce qu'il a dans le ventre.
📜 Un peu d'histoire : 10 jours pour changer le web
Le JavaScript a été créé en 1995 par Brendan Eich alors qu’il travaillait chez Netscape. La légende (vraie !) raconte qu’il a conçu la première version du langage en seulement 10 jours.
À l'origine, il devait s'appeler Mocha, puis LiveScript. Le nom "JavaScript" a finalement été choisi pour surfer sur la popularité du langage Java à l'époque, bien que les deux n'aient techniquement pas grand-chose en commun. Aujourd'hui, son nom officiel pour la standardisation est ECMAScript, mais tout le monde continue de l'appeler JS.
💡 Pourquoi existe-t-il ?
Avant JavaScript, le web était "mort". Les pages étaient de simples documents texte avec des liens (HTML). Pour voir une mise à jour, il fallait recharger toute la page.
JavaScript a été inventé pour apporter de la logique côté client (directement dans votre navigateur). Son rôle est de manipuler le contenu de la page sans avoir à solliciter le serveur à chaque clic.
Pour bien comprendre, on utilise souvent l'analogie de la construction d'une maison :
- HTML : La structure (les murs, les fondations).
- CSS : La décoration (la peinture, les rideaux).
- JavaScript : L'électricité et la plomberie (les lumières qui s'allument, l'eau qui coule quand on tourne le robinet).
🚀 Ce qu'il permet de faire aujourd'hui
Si JavaScript a commencé comme un petit langage pour faire bouger des images ou valider des formulaires, il est devenu un géant omniprésent :
- Interactivité Web : Menus déroulants, cartes interactives (Google Maps), mises à jour de réseaux sociaux en temps réel (le bouton "Like" qui s'incrémente sans recharger la page).
- Côté Serveur (Node.js) : Depuis 2009, JS peut aussi être utilisé pour construire toute la partie invisible des sites (bases de données, serveurs), sortant ainsi du simple navigateur.
- Applications Mobiles : Avec des outils comme React Native, on peut créer des applications pour iPhone et Android en utilisant du JavaScript.
- Jeux Vidéo : De nombreux jeux par navigateur fonctionnent entièrement grâce à lui.
🛠️ Pourquoi est-il si populaire ?
- Accessibilité : Vous n'avez besoin de rien d'autre qu'un navigateur web et un bloc-notes pour commencer à coder.
- Universalité : C'est le seul langage de programmation compris nativement par tous les navigateurs (Chrome, Safari, Firefox).
- Communauté : C'est l'un des langages les plus utilisés au monde, ce qui signifie qu'on trouve de l'aide et des outils (bibliothèques) pour absolument tout.
1) Démarrer rapidement
JavaScript peut s’exécuter:
- Dans le navigateur (pages web)
- Avec Node.js (scripts, serveurs, outils)
Mettre du JS dans une page HTML
Tu as 2 façons courantes: inline (dans la page) ou via un fichier.
1) Script inline (rapide pour tester)
<!doctype html>
<html>
<body>
<h1>Hello</h1>
<script>
console.log('JS chargé');
</script>
</body>
</html>2) Fichier séparé (recommandé)
<script src="./main.js" defer></script>C’est quoi defer ?
defer indique au navigateur:
- Télécharge le script pendant le chargement de la page
- Attends que le HTML soit parsé avant d’exécuter le JS
Résultat: pas besoin de mettre le script tout en bas de la page pour éviter que document.querySelector(...) tombe sur des éléments pas encore créés.
Exemple typique:
<head>
<script src="./main.js" defer></script>
</head>
<body>
<button id="btn">OK</button>
</body>Faut-il ajouter type="text/javascript" ?
En HTML moderne, non: par défaut, <script> est déjà du JavaScript.
- OK (et conseillé):
<script src="./main.js" defer></script>type="text/javascript"est surtout utile pour compatibilité/explicite, mais généralement inutile.
- À connaître:
type="module"sert pour les modules ES (imports/exports).
Petit exemple DOM (avec defer)
<script src="./main.js" defer></script>
<button id="btn">Clique</button>// main.js
const btn = document.querySelector('#btn');
btn.addEventListener('click', () => console.log('clic'));2) Variables et types
constpour des références non réassignées
letpour des variables réassignables
- Éviter
var
const n’est pas immuable, c’est la RÉFÉRENCE qui est constante
- Avec
const, on ne peut pas réassigner la variable vers une nouvelle valeur
- Mais si la valeur est un objet ou un tableau, on peut modifier SON CONTENU
// Interdite: réassignation
const pi = 3.14;
// pi = 3.14159; // TypeError: Assignment to constant variable.
// Autorisée: mutation interne d'un tableau
const nums = [1, 2, 3];
nums.push(4); // [1,2,3,4]
// Autorisée: mutation interne d'un objet
const user = { id: 1, name: 'Ada' };
user.name = 'Grace'; // { id:1, name:'Grace' }
// Copie (nouvelle référence) — OK si affectée à une AUTRE variable
const newNums = [...nums, 5];Points clés:
constgarantit que l’identifiant pointe toujours vers la même référence
- Pour des structures immuables, il faut créer de nouvelles copies (spread, Array.map, etc.)
Pourquoi préférer let et const à var
- Portée:
vara une portée de fonction et fuit les blocs{}
letetconstont une portée de bloc, plus prévisible
- Hoisting:
varest « hoisted » et initialisé àundefined, ce qui peut masquer des bugs
letetconstsont hoisted mais non initialisés avant la « temporal dead zone » (TDZ), ce qui empêche les accès prématurés
- Ré-déclaration:
varpeut être redéclaré dans la même portée sans erreur
letetconstne peuvent pas être redéclarés, ce qui évite des collisions
Exemples:
// var fuit les blocs
if (true) {
var x = 1;
}
console.log(x); // 1 (fuite de bloc)
// let/const respectent le bloc
if (true) {
let y = 2;
}
// console.log(y); // ReferenceError
// Hoisting problématique avec var
console.log(a); // undefined (et pas ReferenceError)
var a = 10;
// TDZ protège contre les usages avant déclaration
// console.log(b); // ReferenceError (TDZ)
let b = 10;
// Redéclaration
var k = 1;
var k = 2; // OK mais dangereux
let m = 1;
// let m = 2; // SyntaxErrorExemples supplémentaires
// Mutation sûre d’un objet const
const settings = { theme: 'light', lang: 'fr' };
settings.theme = 'dark';
// Création d’une nouvelle version immuable
const updatedSettings = { ...settings, lang: 'en' };
// Tableaux: map, filter, reduce créent de nouvelles références
const numbers = [1,2,3,4,5];
const odds = numbers.filter(n => n % 2 === 1); // [1,3,5]
const squared = numbers.map(n => n*n); // [1,4,9,16,25]
const total = numbers.reduce((acc,n) => acc+n, 0); // 15
// const + fonctions fléchées
const add = (a, b) => a + b;
// Déstructuration et valeurs par défaut
const user2 = { id: 2 };
const { name = 'Anonyme' } = user2; // 'Anonyme'
// Attention aux références partagées
const arr1 = [1,2];
const arr2 = arr1; // même référence
arr2.push(3);
console.log(arr1); // [1,2,3]
// Cloner pour éviter les effets de bord
const arr3 = [...arr1];
arr3.push(4);Bonnes pratiques
- Préférer
constpar défaut, puis utiliserletsi la réassignation est nécessaire
- Éviter
varpour réduire les surprises de portée et de hoisting
- Privilégier les copies immuables pour les objets/tableaux
3) Chaînes et nombres
Les chaînes (string) représentent du texte. Les nombres (number) couvrent entiers et décimaux et utilisent un format à virgule flottante.
Points clés avant de coder:
- Chaînes: utilisez les backticks ` pour les template strings avec interpolation et retours à la ligne.
- Nombres: attention aux erreurs d’arrondi en flottant. Utilisez
toFixed,Math.roundet des conversions explicites.
- Conversions:
Number()convertit en nombre,parseIntetparseFloatanalysent depuis le début de la chaîne.
- NaN: utilisez
Number.isNaN(x)pour tester, pasisNaNqui convertit d’abord.
Chaînes — littéraux, interpolation et méthodes courantes
const a = 'Bonjour';
const b = "Monde";
const name = 'Ada';
const msg = `Hello ${name}, today is ${new Date().toLocaleDateString()}`;
// multi‑ligne avec backticks
const poem = `Roses are red\nViolets are blue`;
// Méthodes utiles
' JS '.trim(); // 'JS'
'Ada Lovelace'.toLowerCase(); // 'ada lovelace'
'Ada Lovelace'.includes('love'); // true
'2025-10-16'.split('-'); // ['2025','10','16']
['JS','Vanilla'].join(' '); // 'JS Vanilla'Nombres — conversions, arrondis, Math
Number('42'); // 42
parseInt('42px', 10); // 42 (interprétation en base 10)
parseInt("0xFF", 16); // 255 (interprétation en base 16)
parseFloat('3.14rad'); // 3.14
// Erreurs d’arrondi en flottant
0.1 + 0.2; // 0.30000000000000004
(0.1 + 0.2).toFixed(2); // '0.30'
// Arrondis
Math.round(2.5); // 3
Math.floor(2.9); // 2
Math.ceil(2.1); // 3
// Min/Max aléatoire
Math.min(3, 7, 2); // 2
Math.max(3, 7, 2); // 7
Math.random(); // 0 <= x < 1NaN, Infinity et sécurité des checks
Number('abc'); // NaN
Number.isNaN(Number('abc')); // true
isNaN('abc'); // true (attention: isNaN convertit la chaîne avant)
1 / 0; // Infinity
-1 / 0; // -InfinityPlus d’exemples pratiques
// Formatage décimal contrôlé
const price = 12.3456;
Number(price.toFixed(2)); // 12.35
// Formatage localisé
price.toLocaleString('fr-FR', { style: 'currency', currency: 'EUR' });
// '12,35 €'
// Construire une chaîne lisible
const first = 'Ada', last = 'Lovelace';
const full = `${last.toUpperCase()}, ${first}`; // 'LOVELACE, Ada'
// Extraire le domaine d’un email simple
const email = 'ada@example.com';
const domain = email.split('@')[1]; // 'example.com'
// Compter des occurrences
const text = 'banana';
const countA = [...text].filter(ch => ch === 'a').length; // 34) Tableaux (arrays)
Un tableau est une liste ordonnée de valeurs (indexées à partir de 0). C’est le type le plus courant pour manipuler des collections (liste d’utilisateurs, produits, messages…).
Points clés:
- Accès par index:
arr[0],arr[arr.length - 1]
- Les méthodes comme
map,filter,reducecréent en général un nouveau tableau (pratique pour éviter les effets de bord)
- Les méthodes comme
push,pop,splice,sort,reversemodifient le tableau (mutation)
Création, accès, modification
const nums = [1, 2, 3];
nums[0]; // 1
nums.length; // 3
nums[nums.length - 1]; // 3
nums.push(4); // ajoute à la fin (mutation)
nums.unshift(0); // ajoute au début (mutation)
nums.pop(); // retire le dernier (mutation)
nums.shift(); // retire le premier (mutation)Parcourir (for...of) + index
const names = ['Ada', 'Grace', 'Linus'];
for (const name of names) {
console.log(name);
}
names.forEach((name, i) => {
console.log(i, name);
});Transformer / filtrer / réduire
const xs = [1, 2, 3, 4];
const doubled = xs.map(n => n * 2); // [2,4,6,8]
const evens = xs.filter(n => n % 2 === 0); // [2,4]
const sum = xs.reduce((acc, n) => acc + n, 0); // 10Chercher dans un tableau
const users = [
{ id: 1, name: 'Ada' },
{ id: 2, name: 'Grace' },
];
users.find(u => u.id === 2); // {id:2, name:'Grace'} ou undefined
users.some(u => u.name === 'Ada'); // true
users.every(u => u.id > 0); // true
const letters = ['a', 'b', 'c'];
letters.includes('b'); // trueSlice vs Splice (très utile à connaître)
slice(start, end?): copie une portion (ne mute pas)
splice(start, deleteCount, ...items): modifie le tableau
const arr = ['a', 'b', 'c', 'd'];
const part = arr.slice(1, 3); // ['b','c']
console.log(arr); // ['a','b','c','d']
arr.splice(1, 2, 'X'); // enlève 'b','c' et insère 'X'
console.log(arr); // ['a','X','d']Déstructuration et fusion (spread)
const nums2 = [10, 20, 30, 40];
const [first, ...rest] = nums2; // first=10, rest=[20,30,40]
const merged = [...nums2, 50, 60];
// Copier pour éviter la mutation
const copy = [...nums2];Trier (attention: sort mute et trie comme des strings par défaut)
const scores = [10, 2, 30];
scores.sort(); // [10, 2, 30] (tri "string" => piège)
const sorted = [...scores].sort((a, b) => a - b); // copie + tri numérique5) Objets
Un objet est une structure de données en paires clé → valeur. C’est parfait pour représenter une « chose » (un utilisateur, un produit, une configuration) avec des propriétés nommées.
Points clés:
- Accès: notation point
obj.keyou crochetsobj['key'](utile si la clé est dynamique)
- Ajouter / modifier / supprimer une propriété est simple
- Les objets sont passés par référence: copier avec le spread (
{ ...obj }) pour éviter des effets de bord (copie superficielle)
Créer, lire, écrire
const user = { id: 1, name: 'Ada' };
user.name; // 'Ada'
user['id']; // 1
user.email = 'ada@example.com'; // ajout
user.name = 'Ada Lovelace'; // modification
delete user.email; // suppressionClé dynamique + valeurs par défaut
const settings = { theme: 'dark' };
const key = 'theme';
console.log(settings[key]); // 'dark'
// Valeur par défaut si absent
const lang = settings.lang ?? 'fr';Déstructuration (extraire des propriétés)
const product = { id: 10, title: 'Keyboard', price: 99, currency: 'EUR' };
const { title, price } = product;
// Renommer + valeur par défaut
const { currency: cur = 'EUR', stock = 0 } = product;Spread: copier et mettre à jour (immutabilité)
const original = { id: 1, name: 'Ada', role: 'admin' };
const updated = { ...original, role: 'editor' };
// original n'a pas changéObjet imbriqué (copie superficielle: attention)
const u1 = { name: 'Ada', prefs: { theme: 'dark' } };
const u2 = { ...u1 }; // copie superficielle
u2.prefs.theme = 'light';
console.log(u1.prefs.theme); // 'light' (même sous-objet partagé)
// Solution simple si une seule profondeur:
const u3 = { ...u1, prefs: { ...u1.prefs, theme: 'blue' } };Parcourir un objet
const scores = { alice: 10, bob: 7, clara: 12 };
Object.keys(scores); // ['alice','bob','clara']
Object.values(scores); // [10,7,12]
Object.entries(scores);// [['alice',10], ...]
for (const [name, score] of Object.entries(scores)) {
console.log(name, score);
}Fusionner des objets (attention: dernière valeur gagne)
const defaults = { theme: 'light', lang: 'fr' };
const custom = { theme: 'dark' };
const merged = { ...defaults, ...custom }; // theme='dark', lang='fr'- Références vs copies: objets et tableaux sont passés par référence, utiliser spread pour copier superficiellement
6) Fonctions et portée
Une fonction est un bloc de code réutilisable: tu lui donnes éventuellement des paramètres, et elle renvoie une valeur (ou produit un effet). Comprendre la portée (scope) est crucial: elle détermine où une variable est accessible.
Les différentes façons d’écrire une fonction
Les 3 syntaxes principales font la même chose, mais ont des comportements un peu différents.
// 1) Déclaration de fonction ("function")
function add(a, b) {
return a + b;
}
// 2) Expression de fonction ("function" assignée à une variable)
const add2 = function (a, b) {
return a + b;
};
// 3) Fonction fléchée (recommandée dans la plupart des cas)
const add3 = (a, b) => a + b;Pourquoi on préfère souvent les fonctions fléchées:
- Plus courtes et lisibles (surtout pour les callbacks:
map,filter, événements…)
- Elles n’ont pas leur propre
this(elles capturent lethisdu scope parent), ce qui évite beaucoup de bugs dans le code moderne
- Elles s’utilisent naturellement avec
const(on évite les réassignations involontaires)
Quand garder function:
- Quand tu veux une fonction nommée (debug/stack traces) ou un comportement spécifique de
this/arguments
Points clés:
- Une fonction peut être déclarée de plusieurs façons (déclaration, expression, fléchée)
- Les paramètres peuvent avoir des valeurs par défaut et accepter un nombre variable d’arguments (
...rest)
- Une fonction « voit » les variables de son scope et des scopes parents (closure)
let/constont une portée de bloc, ce qui rend le scope plus prévisible
- Déclaration, expression, fléchées
const add = (a, b) => a + b;
const mul = (a, b) => a * b;
const sub = (a, b) => a - b;
add(2, 3); // 5
add(-1, 4); // 3
add(2.5, 0.75); // 3.25
mul(4, 5); // 20
mul(-3, 6); // -18
mul(2.5, 2); // 5
sub(10, 7); // 3
sub(0, 5); // -5
sub(2.5, 0.5); // 2
// Composition simple
add(mul(2, 3), sub(10, 4)); // add(6, 6) -> 12
// Avec tableaux et map: appliquer add partiellement
const xs = [1, 2, 3];
const plusDeux = x => add(x, 2);
xs.map(plusDeux); // [3, 4, 5]- Paramètres par défaut, rest
greet(name = 'world')utilise un paramètre par défaut. Si aucun argument n’est fourni,nameprend la valeur'world'. Cela évite d’avoir à écrirename = name ?? 'world'dans le corps de la fonction.
sumAll(...xs)utilise le paramètre « rest ». La syntaxe...xsdans la DÉCLARATION de fonction regroupe tous les arguments restants dans un tableau appeléxs. On peut ensuite itérer, réduire, filtrer ce tableau. Exemple, appelersumAll(1,2,3)donnexs = [1,2,3].
- Ne pas confondre « rest » et « spread »:
...en DÉCLARATION de fonction (rest) collecte des valeurs dans un tableau....en APPEL ou en LITTÉRAL (spread) déplie un tableau ou un objet. Par exemplesumAll(...[1,2,3])utilise le spread pour passer 3 arguments séparés.
// Paramètre par défaut: si aucun prénom fourni, on salue 'world'
const greet = (name = 'world') => `Hello ${name}`;
// Rest: accepte un nombre variable d’arguments
const sumAll = (...xs) => xs.reduce((a, n) => a + n, 0);
greet(); // 'Hello world'
greet('Ada'); // 'Hello Ada'
sumAll(1); // 1
sumAll(1, 2, 3); // 6
// Rest vs Spread
const nums = [1, 2, 3];
sumAll(...nums); // 6 (spread côté appel)
// Combiner valeur obligatoire + rest
const labelSum = (label, ...values) => {
const total = values.reduce((a, n) => a + n, 0);
return `${label}: ${total}`;
};
labelSum('Total', 5, 10, 15); // 'Total: 30'const greet = (name = 'world') => `Hello ${name}`;
const sumAll = (...xs) => xs.reduce((a, n) => a + n, 0);- Portée de bloc et closures
const makeCounter = () => {
let x = 0;
return () => ++x;
};
const next = makeCounter();
next(); // 17) DOM et événements (Vanilla)
Le DOM (Document Object Model) est la représentation de la page HTML sous forme d’objets JavaScript. Manipuler le DOM = lire / modifier le contenu, les attributs et les styles, et réagir aux actions utilisateur via des événements.
Points clés:
- Sélectionner des éléments:
getElementById,querySelector,querySelectorAll
- Modifier:
textContent,innerHTML, attributs (setAttribute), classes (classList)
- Créer/insérer/supprimer:
createElement,append,prepend,remove
- Écouter des événements:
addEventListener(click, input, submit, keydown…)
Sélection (querySelector) + modification
<div id="app"></div>
<script>
const app = document.querySelector('#app');
app.textContent = 'Bonjour DOM';
</script>Modifier classes / attributs
const box = document.querySelector('.box');
box.classList.add('active');
box.classList.remove('active');
box.classList.toggle('active');
box.setAttribute('aria-hidden', 'true');
box.getAttribute('aria-hidden');Manipuler le style (à utiliser avec parcimonie)
const title = document.querySelector('h1');
title.style.color = 'tomato';
title.style.fontSize = '32px';Créer et insérer des éléments
const list = document.querySelector('#list');
const li = document.createElement('li');
li.textContent = 'Nouveau point';
list.append(li); // ajoute à la finExemple: rendre une liste depuis un tableau
<ul id="todos"></ul>
<script>
const todos = ['Apprendre DOM', 'Faire un mini-projet', 'Comprendre events'];
const ul = document.querySelector('#todos');
ul.innerHTML = todos.map(t => `<li>${t}</li>`).join('');
</script>Événements: click + prévention par défaut (submit)
<form id="form">
<input id="name" placeholder="Ton nom" />
<button>Envoyer</button>
</form>
<script>
const form = document.querySelector('#form');
const input = document.querySelector('#name');
form.addEventListener('submit', (e) => {
e.preventDefault();
console.log('Nom:', input.value);
});
</script>Délégation d'événements (très pratique pour des listes dynamiques)
<ul id="list"></ul>
<script>
const ul = document.querySelector('#list');
ul.innerHTML = ['A', 'B', 'C'].map(x => `<li><button class="remove" data-value="${x}">Supprimer ${x}</button></li>`).join('');
ul.addEventListener('click', (e) => {
const btn = e.target.closest('.remove');
if (!btn) return;
const value = btn.dataset.value; // 'A', 'B', ...
btn.closest('li').remove();
console.log('Supprimé:', value);
});
</script>8) Stockage Web: localStorage et sessionStorage
Le Web Storage permet de stocker de petites données côté navigateur sous forme de paires clé → valeur (des strings). Deux stockages existent:
localStorage: persiste même après fermeture/relance du navigateur
sessionStorage: persiste seulement pendant l’onglet (ou la fenêtre) en cours
Points clés:
- Les valeurs sont des strings → pour stocker des objets/tableaux, on utilise
JSON.stringify/JSON.parse
- Limité à quelques Mo (selon navigateur)
- Accessible depuis le JS de la page (donc pas adapté à des secrets)
Exemples de base (set/get/remove/clear)
// Écrire
localStorage.setItem('theme', 'dark');
sessionStorage.setItem('draft', 'Bonjour');
// Lire
const theme = localStorage.getItem('theme'); // 'dark' ou null
// Supprimer une clé
localStorage.removeItem('theme');
// Vider tout le stockage
sessionStorage.clear();Stocker un objet (JSON)
const user = { id: 1, name: 'Ada', roles: ['admin'] };
localStorage.setItem('user', JSON.stringify(user));
const raw = localStorage.getItem('user');
const parsed = raw ? JSON.parse(raw) : null;
console.log(parsed?.name); // 'Ada'Petit exemple pratique: garder un formulaire en brouillon (sessionStorage)
const input = document.querySelector('#message');
// Restaurer au chargement
input.value = sessionStorage.getItem('draftMessage') ?? '';
// Sauvegarder à chaque saisie
input.addEventListener('input', () => {
sessionStorage.setItem('draftMessage', input.value);
});
// Optionnel: effacer quand on « envoie »
function submit() {
// ... envoi
sessionStorage.removeItem('draftMessage');
}9) Asynchrone, fetch et JSON
Comprendre l’asynchrone en JavaScript est essentiel pour les appels réseau, les timers et les opérations coûteuses. Deux concepts clés: les Promises et la syntaxe async/await.
Promises — l’idée
- Une Promise représente une opération en cours qui aboutira plus tard avec une valeur (résolue) ou une erreur (rejetée).
- États: pending → fulfilled ou rejected.
- On consomme une Promise avec
.then(...)pour la réussite et.catch(...)pour l’échec.
// Exemple: une Promise qui résout après un délai
const delay = ms => new Promise((resolve) => setTimeout(resolve, ms));
delay(200).then(() => console.log('200 ms passées')).catch(console.error);async/await — sucre syntaxique sur les Promises
asyncmarque une fonction comme asynchrone. Elle retourne toujours une Promise.
awaitsuspend l’exécution de la fonctionasyncjusqu’à résolution de la Promise attendue, puis renvoie sa valeur.
- Avantage: code plus lisible et linéaire que les chaînes de
.then(...).
async function demo() {
await delay(200); // attend 200 ms
return 'ok'; // implicite: Promise résolue avec 'ok'
}
demo().then(console.log); // 'ok'fetch — faire une requête HTTP
fetch(url, options?)retourne une Promise d’un objetResponse.
response.okindique succès HTTP (statut 200–299).
- Pour lire le corps:
response.json(),response.text(), etc. Ces méthodes sont aussi asynchrones et retournent des Promises.
async function getPosts() {
const response = await fetch('https://jsonplaceholder.typicode.com/posts');
if (!response.ok) {
// Par exemple 404, 500...
throw new Error('HTTP ' + response.status);
}
const data = await response.json(); // parse JSON → objet JS
return data; // tableau de posts
}try / catch / finally — gérer les erreurs avec await
try { ... } catch (err) { ... }permet d’attraper les erreurs lancées avecthrowou issues d’une Promise rejetée attendue avecawait.
finally { ... }s’exécute toujours, succès ou erreur, pratique pour nettoyer l’UI, arrêter un spinner, etc.
async function showPosts() {
const listEl = document.getElementById('posts');
const spinner = document.getElementById('spinner');
spinner.style.display = 'block';
try {
const posts = await getPosts();
listEl.innerHTML = posts.slice(0, 5).map(p => `<li>${p.title}</li>`).join('');
} catch (err) {
console.error(err);
listEl.textContent = 'Erreur de chargement';
} finally {
spinner.style.display = 'none';
}
}Bonnes pratiques asynchrone
- Toujours vérifier
response.okavant de lire le corps.
- Enchaîner plusieurs awaits dans un
try/catchunique quand ils dépendent les uns des autres.
- Pour lancer plusieurs requêtes indépendantes plus vite, utiliser
Promise.all([...]).
async function loadBoth() {
const [users, posts] = await Promise.all([
fetch('https://jsonplaceholder.typicode.com/users').then(r => r.json()),
fetch('https://jsonplaceholder.typicode.com/posts').then(r => r.json()),
]);
console.log(users.length, posts.length);
}10) Modules ES
Les modules ES (ECMAScript Modules, ESM) sont le standard moderne pour découper ton code JavaScript en plusieurs fichiers, puis importer / exporter des fonctions, variables ou classes entre ces fichiers.
Pourquoi c’est utile:
- Organisation: un fichier = une responsabilité (ex:
utils.js,api.js,dom.js)
- Réutilisation: tu exportes des morceaux de code et tu les réutilises ailleurs
- Encapsulation: ce qui n’est pas exporté reste privé au module
- Chargement fiable: les imports sont résolus avant l’exécution (plus prévisible)
Export / import (le cas le plus courant)
// utils.js
export const capitalize = s => s[0].toUpperCase() + s.slice(1);
// main.js
import { capitalize } from './utils.js';
console.log(capitalize('vanilla'));Export par défaut (default export)
Utile quand un fichier expose « une chose principale ».
// logger.js
export default function log(msg) {
console.log('[LOG]', msg);
}
// main.js
import log from './logger.js';
log('hello');Points importants
- En navigateur, il faut utiliser
type="module":
<script type="module" src="./main.js"></script>- Les imports utilisent en général un chemin relatif (
./ou../) et, selon l’environnement, l’extension.jsest requise.
- Chaque module a sa propre portée (scope): pas de variables globales « par accident ».
