Spread Operator (...)
Le spread operator ... permet de "déplier" les éléments d'un tableau ou d'un objet pour créer de nouvelles copies sans modifier les originaux.
Avec les objets
Copier un objet
const user = { name: 'Alice', age: 25 };
const copy = { ...user };
console.log(copy); // { name: 'Alice', age: 25 }
Modifier une propriété
const user = { name: 'Alice', age: 25 };
const updated = { ...user, age: 26 };
console.log(updated); // { name: 'Alice', age: 26 }
console.log(user); // { name: 'Alice', age: 25 } (inchangé)
Fusionner des objets
const person = { name: 'Bob', age: 30 };
const address = { city: 'Paris', country: 'France' };
const complete = { ...person, ...address };
console.log(complete);
// { name: 'Bob', age: 30, city: 'Paris', country: 'France' }
Ordre important
const user = { name: 'Alice', age: 25 };
// Les propriétés après écrasent les précédentes
const updated1 = { ...user, age: 26 };
// { name: 'Alice', age: 26 }
const updated2 = { age: 26, ...user };
// { age: 25, name: 'Alice' } (user.age écrase 26)
Quelle est la différence entre { ...user, age: 26 } et { age: 26, ...user } ?
Avec les tableaux
Fusionner des tableaux
const arr1 = [1, 2];
const arr2 = [3, 4];
const merged = [...arr1, ...arr2];
console.log(merged); // [1, 2, 3, 4]
Copier un tableau
const original = [1, 2, 3];
const copy = [...original];
console.log(copy); // [1, 2, 3]
console.log(copy === original); // false (nouvelle référence)
Ajouter des éléments
const arr1 = [1, 2, 3];
// Au début
const extended = [0, ...arr1]; // [0, 1, 2, 3]
// À la fin
const extended = [...arr1, 4, 5]; // [1, 2, 3, 4, 5]
// Au milieu
const extended = [...arr1.slice(0, 2), 99, ...arr1.slice(2)];
// [1, 2, 99, 3]
Immutabilité
Le spread operator permet de créer de nouvelles copies au lieu de modifier les originaux. C'est une pratique essentielle pour éviter les effets de bord.
// Mutation directe
const numbers = [1, 2, 3];
numbers.push(4);
console.log(numbers); // [1, 2, 3, 4] - modifié
// Immutabilité avec spread
const numbers = [1, 2, 3];
const newNumbers = [...numbers, 4];
console.log(numbers); // [1, 2, 3] - inchangé
console.log(newNumbers); // [1, 2, 3, 4]
Que se passe-t-il avec : const copy = [...original] ?
Exemples pratiques
Ajouter un élément à un tableau
const items = [1, 2, 3];
// Ajouter à la fin
const withFour = [...items, 4];
console.log(withFour); // [1, 2, 3, 4]
// Ajouter au début
const withZero = [0, ...items];
console.log(withZero); // [0, 1, 2, 3]
Retirer un élément d'un tableau
const items = [1, 2, 3, 4, 5];
// Retirer par index
const removeAtIndex = (arr, index) => {
return [
...arr.slice(0, index),
...arr.slice(index + 1)
];
};
console.log(removeAtIndex(items, 2)); // [1, 2, 4, 5]
// Retirer par valeur
const removeValue = (arr, value) => {
return arr.filter(item => item !== value);
};
console.log(removeValue(items, 3)); // [1, 2, 4, 5]
Modifier un élément dans un tableau
const todos = [
{ id: 1, text: 'Apprendre JavaScript', done: false },
{ id: 2, text: 'Faire les courses', done: false }
];
// Marquer un todo comme terminé
const toggleTodo = (todos, id) => {
return todos.map(todo =>
todo.id === id
? { ...todo, done: !todo.done }
: todo
);
};
console.log(toggleTodo(todos, 1));
// [{ id: 1, text: 'Apprendre JavaScript', done: true }, ...]
Mettre à jour un objet imbriqué
const user = {
name: 'Alice',
address: {
city: 'Paris',
country: 'France'
}
};
// Changer la ville (spread à chaque niveau)
const updatedUser = {
...user,
address: {
...user.address,
city: 'Lyon'
}
};
console.log(updatedUser.address.city); // 'Lyon'
console.log(user.address.city); // 'Paris' (inchangé)
Shallow copy (copie superficielle)
Le spread operator fait une copie superficielle (shallow copy). Les objets imbriqués sont partagés par référence :
const user = {
name: 'Alice',
address: { city: 'Paris' }
};
const copy = { ...user };
copy.address.city = 'Lyon';
console.log(user.address.city); // 'Lyon' (modifié aussi!)
Solutions :
- Utiliser le spread à chaque niveau (manuel)
const copy = {
...user,
address: { ...user.address }
};
copy.address.city = 'Lyon';
console.log(user.address.city); // 'Paris' (inchangé)
- Utiliser
structuredClone()
const copy = structuredClone(user);
copy.address.city = 'Lyon';
console.log(user.address.city); // 'Paris' (inchangé)
structuredClone() fait une copie profonde (deep copy) de tout l'objet, y compris les objets imbriqués. C'est la solution la plus simple et la plus sûre pour copier des objets complexes.
Limites de structuredClone() :
- Ne copie pas les fonctions
- Ne copie pas les symboles
- Ne copie pas les prototypes
Pour la plupart des cas d'usage (données JSON, objets simples), structuredClone() est parfait.
Que se passe-t-il si vous modifiez une propriété imbriquée après avoir utilisé le spread operator ?
Rest vs Spread
Même syntaxe ... mais usages différents :
// Spread : déplier
const arr = [1, 2, 3];
console.log(...arr); // 1 2 3
// Rest : collecter
const [first, ...rest] = arr;
console.log(first); // 1
console.log(rest); // [2, 3]
Quelle est la différence entre spread et rest operator ?
Comprendre, pas mémoriser
Ce qu'il faut retenir :
- Spread operator :
...pour déplier des éléments - Copier :
[...arr]pour tableaux,{ ...obj }pour objets - Fusionner :
[...arr1, ...arr2]ou{ ...obj1, ...obj2 } - Immutabilité : créer de nouvelles copies au lieu de modifier les originaux
- Shallow copy : attention aux objets imbriqués (utiliser
structuredClone()ou spread à chaque niveau) - Ordre compte :
{ ...user, age: 26 }écrase age,{ age: 26, ...user }garde l'age de user
Le spread operator est omniprésent pour manipuler des données de manière immutable.
Exercice : Pratique : Spread Operator
Avec ces données :
const cart = [
{ id: 1, name: 'Laptop', price: 1000 },
{ id: 2, name: 'Mouse', price: 25 }
];
const user = {
name: 'Alice',
email: 'alice@example.com',
preferences: {
theme: 'dark',
language: 'fr'
}
};
- Ajouter un nouveau produit
{ id: 3, name: 'Keyboard', price: 75 }au panier - Modifier le prix du premier produit à 850€ (sans modifier l'original)
- Ajouter une propriété
age: 25àuser(sans modifier l'original) - Changer
preferences.themeà'light'(sans modifier l'original)
Astuce : Utilisez le spread operator et .map() pour les modifications dans les tableaux.