Apprendre JavaScript de zéro jusqu'au niveau expert : syntaxe moderne, DOM, asynchrone et event loop, modules, prototypes, métaprogrammation, performance et mémoire.
Les données réelles arrivent presque toujours sous forme de tableaux d'objets : une réponse d'API, une liste de produits, des lignes de CSV. Savoir les transformer en quelques lignes lisibles est la compétence la plus utilisée au quotidien.
const nom = 'Ada'
const user = {
nom, // raccourci pour nom: nom
age: 36,
'clé avec espace': true,
['role_' + 1]: 'admin', // clé calculée
saluer() { // méthode
return `Je suis ${this.nom}`
},
}
user.age // 36
user['clé avec espace'] // true
user.email // undefined
delete user.age
'nom' in user // true
Object.hasOwn(user, 'nom') // trueconst { nom, age = 0, adresse: { ville } = {} } = user
const [premier, , troisieme, ...reste] = [10, 20, 30, 40, 50]
function afficher({ nom, email = 'n/a' }) {
console.log(nom, email)
}const defaults = { theme: 'clair', langue: 'fr' }
const prefs = { ...defaults, theme: 'sombre' } // { theme: 'sombre', langue: 'fr' }Le spread fait une copie superficielle. Pour une copie profonde, structuredClone :
const original = { tags: ['a'], date: new Date() }
const copie = structuredClone(original)
copie.tags.push('b')
original.tags // ['a']Object.keys(prefs) // ['theme', 'langue']
Object.values(prefs) // ['sombre', 'fr']
Object.entries(prefs) // [['theme', 'sombre'], ['langue', 'fr']]
// Transformer un objet
const enMajuscules = Object.fromEntries(
Object.entries(prefs).map(([k, v]) => [k, v.toUpperCase()])
)const CONFIG = Object.freeze({ api: 'https://api.exemple.fr' })
CONFIG.api = 'autre' // ignoré (TypeError en mode strict)Object.freeze est superficiel : les objets imbriqués restent modifiables.
const nums = [5, 3, 8]
nums.push(1) // ajoute à la fin
nums.pop() // retire à la fin
nums.unshift(0) // ajoute au début
nums.shift() // retire au début
nums.includes(3) // true
nums.indexOf(8) // 2
nums.at(-1) // 8
nums.slice(0, 2) // [5, 3] — copie
nums.splice(1, 1) // retire 1 élément à l'index 1 — MUTE le tableau
Array.from({ length: 3 }, (_, i) => i * 2) // [0, 2, 4]C'est la source d'une quantité énorme de bugs, en particulier avec React où l'état ne doit jamais être muté.
| Mute le tableau | Renvoie une copie (ES2023+) |
|---|---|
sort() | toSorted() |
reverse() | toReversed() |
splice() | toSpliced() |
arr[i] = x | with(i, x) |
const notes = [12, 8, 15]
const triees = notes.toSorted((a, b) => a - b) // [8, 12, 15], notes intactsort() sans comparateur trie en ordre lexicographique : [10, 9, 1].sort() donne [1, 10, 9]. Passez toujours une fonction de comparaison pour des nombres.
const commandes = [
{ id: 1, client: 'Ada', total: 120, statut: 'payee' },
{ id: 2, client: 'Linus', total: 45, statut: 'annulee' },
{ id: 3, client: 'Ada', total: 80, statut: 'payee' },
{ id: 4, client: 'Grace', total: 200, statut: 'payee' },
]
commandes.map(c => c.total) // [120, 45, 80, 200]
commandes.filter(c => c.statut === 'payee') // 3 commandes
commandes.find(c => c.client === 'Grace') // { id: 4, ... }
commandes.findLast(c => c.client === 'Ada') // { id: 3, ... }
commandes.some(c => c.total > 150) // true
commandes.every(c => c.total > 10) // true
commandes.reduce((s, c) => s + c.total, 0) // 445
commandes.flatMap(c => [c.id, c.total]) // [1, 120, 2, 45, ...]Regrouper, avec Object.groupBy (ES2024) :
const parClient = Object.groupBy(commandes, c => c.client)
// { Ada: [...2 commandes], Linus: [...], Grace: [...] }
const caParClient = Object.fromEntries(
Object.entries(parClient).map(([client, cmds]) => [
client,
cmds.reduce((s, c) => s + c.total, 0),
])
)
// { Ada: 200, Linus: 45, Grace: 200 }Map est un dictionnaire dont les clés peuvent être de n'importe quel type, qui garde l'ordre d'insertion et expose sa taille.
const visites = new Map()
visites.set('/accueil', 10)
visites.set('/blog', 3)
visites.get('/blog') // 3
visites.has('/contact') // false
visites.size // 2
visites.delete('/blog')
const elementsVus = new Map()
elementsVus.set(document.body, Date.now()) // un objet comme cléQuand utiliser Map plutôt qu'un objet ? Dès que les clés sont dynamiques (issues de données utilisateur) ou non-string, ou quand on ajoute et supprime souvent. Un objet peut entrer en collision avec des clés comme __proto__ ou constructor.
const tags = new Set(['js', 'web', 'js'])
tags.size // 2
tags.add('node')
tags.has('web') // true
const uniques = [...new Set([1, 2, 2, 3])] // [1, 2, 3]Opérations ensemblistes natives (ES2025) :
const a = new Set([1, 2, 3])
const b = new Set([2, 3, 4])
a.union(b) // Set {1, 2, 3, 4}
a.intersection(b) // Set {2, 3}
a.difference(b) // Set {1}
a.isSubsetOf(b) // falseconst json = JSON.stringify({ nom: 'Ada', date: new Date(0) }, null, 2)
const obj = JSON.parse(json)
obj.date // '1970-01-01T00:00:00.000Z' — une string, plus une DateJSON.stringify ignore les fonctions, undefined et les Symbol, et convertit les dates en chaînes. Map et Set deviennent {}. C'est pour cela qu'on préfère structuredClone à JSON.parse(JSON.stringify(x)) pour cloner.
À partir du tableau commandes ci-dessus, calculer pour les commandes payées : le chiffre d'affaires total, le panier moyen, et le meilleur client.
const payees = commandes.filter(c => c.statut === 'payee')
const ca = payees.reduce((s, c) => s + c.total, 0)
const panierMoyen = ca / payees.length
const parClient = new Map()
for (const { client, total } of payees) {
parClient.set(client, (parClient.get(client) ?? 0) + total)
}
const [meilleur] = [...parClient].toSorted((a, b) => b[1] - a[1])
console.log({ ca, panierMoyen, meilleur })
// { ca: 400, panierMoyen: 133.33333333333334, meilleur: ['Ada', 200] }Map pour les dictionnaires dynamiques, Set pour l'unicité, méthodes non mutantes pour les transformations. Avec map, filter et reduce bien en main, la plupart des traitements de données tiennent en une chaîne de trois lignes.