14

Spread & Rest

L'opérateur ... (trois points)

L'opérateur ... est l'un des ajouts les plus puissants d'ES6. Il a deux rôles opposés selon le contexte : Spread (expansion) et Rest (collecte).

🔄 Spread vs Rest : Même syntaxe, contextes opposés

SPREAD
Expansion (Donner)

Décompose un iterable en éléments individuels.

const arr = [1, 2, 3];
console.log(...arr);  // 1 2 3

const obj = { a: 1, b: 2 };
const copy = { ...obj };  // Clone
Contextes : Arguments de fonction, tableaux, objets
REST
Collecte (Recevoir)

Rassemble plusieurs éléments en un tableau.

function sum(...numbers) {
    return numbers.reduce((a, b) => a + b);
}
sum(1, 2, 3);  // numbers = [1,2,3]
Contextes : Paramètres de fonction, destructuring

📤 Patterns Spread (Expansion)

// 1. SPREAD DANS LES TABLEAUX
const arr1 = [1, 2, 3];
const arr2 = [4, 5, 6];

// Concaténation
const combined = [...arr1, ...arr2];  // [1,2,3,4,5,6]

// Insertion au milieu
const inserted = [...arr1, 99, ...arr2];  // [1,2,3,99,4,5,6]

// Clone superficiel
const clone = [...arr1];  // Nouveau tableau

// 2. SPREAD DANS LES OBJETS
const user = { name: 'Alice', age: 25 };
const location = { city: 'Paris', country: 'France' };

// Fusion d'objets
const profile = { ...user, ...location };
// { name: 'Alice', age: 25, city: 'Paris', country: 'France' }

// Override de propriétés (ordre important !)
const updated = { ...user, age: 26 };  // age écrasé
const wrong = { age: 26, ...user };    // age de user gagne

// 3. SPREAD DANS LES APPELS DE FONCTION
const numbers = [5, 2, 8, 1];
Math.max(...numbers);  // 8 (au lieu de Math.max(5,2,8,1))

// Équivalent à :
Math.max.apply(null, numbers);  // Ancienne méthode

📥 Patterns Rest (Collecte)

// 1. REST DANS LES PARAMÈTRES
function logAll(...args) {
    console.log('Nombre d\'args:', args.length);
    args.forEach(arg => console.log(arg));
}
logAll('a', 'b', 'c');  // args = ['a', 'b', 'c']

// Combiné avec paramètres normaux (rest DOIT être dernier)
function greet(greeting, ...names) {
    return `${greeting} ${names.join(', ')}`;
}
greet('Hello', 'Alice', 'Bob');  // "Hello Alice, Bob"

// 2. REST DANS LE DESTRUCTURING (Arrays)
const [first, second, ...others] = [1, 2, 3, 4, 5];
// first = 1, second = 2, others = [3, 4, 5]

const [head, ...tail] = [10, 20, 30];
// head = 10, tail = [20, 30]

// 3. REST DANS LE DESTRUCTURING (Objects)
const person = { name: 'Bob', age: 30, city: 'Lyon', job: 'Dev' };
const { name, age, ...rest } = person;
// name = 'Bob', age = 30, rest = { city: 'Lyon', job: 'Dev' }

// Utile pour extraire certaines props
const { password, ...publicData } = userFromDB;
// Retire password, garde le reste

🎮 Visualiseur Spread/Rest

Testez différents patterns et voyez le résultat.

Cliquez sur un bouton pour voir la démo

💼 Cas d'Usage Pratiques

// 1. CLONER ET MODIFIER UN OBJET (Immutabilité)
const originalState = { count: 0, user: 'Alice' };
const newState = { ...originalState, count: 1 };
// originalState inchangé, newState = { count: 1, user: 'Alice' }

// 2. AJOUTER UN ÉLÉMENT À UN TABLEAU (Immutable)
const todos = ['Task 1', 'Task 2'];
const newTodos = [...todos, 'Task 3'];  // Pas de .push()

// 3. RETIRER UNE PROPRIÉTÉ D'UN OBJET
const { password, ...safeUser } = user;
// safeUser n'a plus password

// 4. FUSIONNER DES CONFIGS
const defaultConfig = { theme: 'dark', lang: 'fr', timeout: 5000 };
const userConfig = { lang: 'en', timeout: 3000 };
const finalConfig = { ...defaultConfig, ...userConfig };
// { theme: 'dark', lang: 'en', timeout: 3000 }

// 5. FONCTION VARIADIC (nombre variable d'args)
function createURL(base, ...segments) {
    return base + '/' + segments.join('/');
}
createURL('https://api.com', 'users', '123', 'posts');
// "https://api.com/users/123/posts"

// 6. CONVERTIR ARGUMENTS EN ARRAY
function oldStyle() {
    const args = [...arguments];  // arguments n'est pas un vrai array
    return args.map(x => x * 2);
}

// Mieux : utiliser rest directement
function modernStyle(...args) {
    return args.map(x => x * 2);
}

⚖️ Spread vs Méthodes Traditionnelles

Opération Ancienne Méthode Avec Spread/Rest
Concaténer arrays arr1.concat(arr2) [...arr1, ...arr2]
Cloner array arr.slice() [...arr]
Cloner objet Object.assign({}, obj) { ...obj }
Max d'un array Math.max.apply(null, arr) Math.max(...arr)
Args variables arguments (pseudo-array) ...args (vrai array)
⚠️ Pièges Courants :
  • Clone superficiel uniquement : {...obj} ne clone pas les objets imbriqués (shallow copy).
  • Rest doit être dernier : function f(...args, x) ❌ Erreur syntaxe.
  • Ordre important pour objets : { ...a, ...b } → les props de b écrasent a.
  • Performance : Spread crée de nouveaux objets/arrays. Pour de grandes structures, considérez des alternatives.
Best Practice : Utilisez spread/rest pour l'immutabilité (React, Redux). Préférez ...rest à arguments. Pour les clones profonds, utilisez structuredClone() ou une bibliothèque.
← Storage Suivant: Classes →