Qu’est-ce que l’ES6+ ?
En juin 2015, JavaScript a reçu sa mise à jour la plus importante de son histoire. ECMAScript 2015, mieux connu sous le nom d’ES6, a introduit la portée de bloc (block scoping), les fonctions fléchées, les classes, les modules, les promesses et bien plus encore. Le comité qui maintient le langage s’est ensuite engagé à publier une nouvelle édition chaque année, et le terme « ES6+ » est devenu l’abréviation désignant l’ensemble de cette ère moderne.
Il n’est pas nécessaire d’apprendre chaque fonctionnalité. Une poignée d’entre elles représentent la vaste majorité du code écrit quotidiennement, et c’est ce que ce guide couvre. Le fil conducteur de toutes ces nouveautés est simple : exprimer son intention avec moins de cérémonie.
let et const
La fonctionnalité la plus ancienne est aussi la plus importante. var a une portée de fonction (function-scoped) et subit un hoisting qui peut surprendre. let et const ont une portée de bloc (block-scoped), elles n’existent donc qu’à l’intérieur du { } le plus proche.
// scope.js
if (true) {
let message = "inside";
const limit = 10;
}
// message and limit are not defined out here
const empêche la réassignation de la liaison, ce qui rend votre intention évidente : ce nom ne pointera pas vers un autre endroit. Cela ne gèle pas la valeur, donc un tableau const peut toujours être muté. Utilisez const par défaut, let lorsqu’une réassignation est nécessaire, et considérez var comme faisant partie de l’histoire.
Fonctions fléchées
Les fonctions fléchées offrent une syntaxe plus courte avec une différence de comportement majeure : elles n’ont pas leur propre this. Elles héritent de this du scope environnant, ce qui est presque toujours le comportement souhaité dans les callbacks.
// arrows.js
const add = (a, b) => a + b;
const square = (n) => {
return n * n;
};
const names = ["Ada", "Grace", "Linus"];
const upper = names.map((name) => name.toUpperCase());
Lorsque le corps de la fonction est une expression unique, les accolades et le return peuvent être omis. Les parenthèses autour d’un paramètre unique sont facultatives. Comme les fonctions fléchées capturent this, elles sont idéales pour les gestionnaires d’événements et les méthodes de tableaux, mais peu adaptées pour les méthodes d’objets qui nécessitent leur propre this.
Template literals
Les backticks permettent de créer des chaînes de caractères sur plusieurs lignes et d’interpoler des expressions avec ${ }.
// message.js
const name = "Ada";
const role = "engineer";
const greeting = `Hello, ${name}!
You are logged in as a ${role}.`;
Les template literals supportent également les tagged templates, où une fonction reçoit séparément les parties littérales et les valeurs interpolées. Ce mécanisme est à la base de nombreuses bibliothèques de templating et de styling.
Destructuration
La destructuration permet d’extraire des valeurs d’arrays et d’objets pour les assigner à des variables, ce qui évite bien des répétitions lors de l’accès aux propriétés.
// destructure.js
const user = { name: "Ada", age: 36, city: "London" };
const { name, age, city = "Unknown" } = user;
const coords = [51.5, -0.12];
const [lat, lng] = coords;
function greet({ name }) {
return `Hello, ${name}`;
}
Vous pouvez renommer les variables lors de la destructuration (const { name: userName } = user), définir des valeurs par défaut, ou destructurer directement dans la liste des paramètres d’une fonction — un pattern utilisé constamment avec les props React et les objets de configuration.
Spread et rest
Les trois points effectuent deux tâches complémentaires selon l’endroit où ils apparaissent.
// spread.js
const a = [1, 2, 3];
const b = [4, 5];
const combined = [...a, ...b]; // spread: expand
const copy = { ...user, age: 37 }; // shallow clone + override
function sum(...numbers) { // rest: collect
return numbers.reduce((t, n) => t + n, 0);
}
Le spread copie des éléments dans un nouveau tableau ou objet, ce qui constitue la base des mises à jour immuables. Le rest regroupe les arguments ou éléments restants dans un seul tableau. Ensemble, ils rendent la manipulation des collections beaucoup plus agréable.
Paramètres par défaut et raccourcis
Les fonctions peuvent déclarer des valeurs par défaut, et les littéraux d’objets peuvent utiliser des raccourcis lorsque le nom de la propriété correspond à celui d’une variable.
// config.js
function connect({ host = "localhost", port = 8080 } = {}) {
return `${host}:${port}`;
}
const name = "Ada";
const user = { name, greet() { return `Hi, ${this.name}`; } };
Les valeurs par défaut ne sont évaluées que lorsque l’argument est undefined, ce qui correspond généralement au comportement attendu. Les propriétés et méthodes raccourcies permettent d’alléger le code faisant un usage intensif d’objets.
Optional chaining et nullish coalescing
Ces deux opérateurs, ajoutés en 2020, ont permis d’éliminer des tonnes de vérifications défensives.
// safe.js
const city = user?.address?.city;
const name = input ?? "anonymous";
user?.profile?.onLogin?.();
?. s’arrête prématurément (short-circuit) et renvoie undefined si la valeur à sa gauche est null ou undefined. ?? fournit une valeur de secours uniquement lorsque le côté gauche est null ou undefined — contrairement à ||, il ne considère pas 0, "" ou false comme des valeurs manquantes.
Méthodes d’Array
Le prototype d’Array regorge de méthodes qui décrivent l’intention plutôt que la mécanique de boucle.
// arrays.js
const products = [
{ name: "Keyboard", price: 80, inStock: true },
{ name: "Mouse", price: 40, inStock: false },
{ name: "Cable", price: 10, inStock: true },
];
const names = products.map((p) => p.name);
const cheap = products.filter((p) => p.price < 50);
const total = products.reduce((sum, p) => sum + p.price, 0);
const available = products.some((p) => p.inStock);
const allCheap = products.every((p) => p.price < 100);
const mouse = products.find((p) => p.name === "Mouse");
map transforme, filter sélectionne, reduce réduit une liste en une seule valeur, find retourne la première correspondance, et some/every testent une condition. Elles peuvent être chaînées, ne mutent pas le tableau d’origine et se lisent comme une description de ce que vous souhaitez accomplir.
Modules
Les modules ES vous permettent de répartir votre code sur plusieurs fichiers et de ne partager que les éléments de votre choix.
// math.js
export function add(a, b) {
return a + b;
}
export const PI = 3.14159;
export default function subtract(a, b) {
return a - b;
}
// app.js
import subtract, { add, PI } from "./math.js";
Les exports nommés peuvent être multiples par fichier et sont importés par leur nom. Un export par défaut est une valeur principale unique. Les modules possèdent leur propre portée, sont évalués une seule fois et permettent aux bundlers de supprimer le code inutilisé grâce au tree-shaking.
Classes
Les classes offrent une syntaxe claire pour le code orienté objet, s’appuyant sur le système de prototypes existant de JavaScript.
// user.js
class User {
#secret = "hidden"; // private field
constructor(name) {
this.name = name;
}
get greeting() {
return `Hello, ${this.name}`;
}
static create(name) {
return new User(name);
}
}
class Admin extends User {
constructor(name) {
super(name);
this.role = "admin";
}
}
extends et super gèrent l’héritage, static définit des méthodes sur la classe elle-même, et # marque les champs véritablement privés. Sous le capot, il s’agit toujours de prototypes, mais la syntaxe est beaucoup plus facile à lire.
Autres fonctionnalités à connaître
- Map et Set pour les collections avec clés et les valeurs uniques, offrant une meilleure sémantique que les objets et tableaux classiques pour ces usages.
- for…of pour itérer sur les tableaux, les chaînes de caractères, les maps, les sets et tout autre itérable.
- L’exponentiation avec
**, ainsi2 ** 10remplaceMath.pow(2, 10). - Les itérateurs et générateurs pour les séquences paresseuses (lazy sequences), l’itération personnalisée et les fonctions pouvant être mises en pause.
- Object.entries / fromEntries pour convertir des objets en tableaux de paires et inversement.
Bonnes pratiques
- Utilisez
constpar défaut ; réservezletuniquement pour les réassignations. - Privilégiez les arrow functions pour les callbacks, et les fonctions classiques pour les méthodes nécessitant
this. - Utilisez la déstructuration dans les paramètres pour rendre la structure requise explicite.
- Utilisez l’opérateur spread pour les mises à jour immuables plutôt que de muter des données partagées.
- Tournez-vous vers
?.et??avant d’écrire des guards imbriqués. - Privilégiez les méthodes de tableau aux boucles manuelles lors de la transformation de données.
- Gardez vos modules concis et exportez le minimum d’interface possible.
Erreurs courantes
- Croire que
constrend un objet immuable — cela empêche seulement la réaffectation. - Utiliser une fonction fléchée comme méthode d’objet et perdre le contexte de
this. - Utiliser
||pour des valeurs par défaut alors que0ou""sont des valeurs valides ; utilisez??. - Effectuer un spread sur un seul niveau en s’attendant à obtenir un clone profond.
- Mélanger
requireetimportdans le même système de modules sans comprendre l’interopérabilité. - Chaîner trop de méthodes de tableau, rendant le pipeline illisible.
Et après ?
La syntaxe moderne est votre vocabulaire ; le DOM et le JavaScript asynchrone sont les outils pour le mettre en pratique. Une fois que les promesses et les modules vous seront familiers, la Fetch API vous permettra de transformer ces compétences en véritables applications.