Une seule syntaxe, deux rôles opposés
Les trois petits points ... reviennent sans arrêt en JavaScript moderne, et selon l'endroit où on les place, ils font deux choses exactement inverses. Une fois qu'on a repéré la logique, toute utilisation de l'opérateur ... en JavaScript rentre dans l'une de ces deux cases :
- Rest :
...nomcôté réception regroupe plusieurs valeurs dans un seul tableau ou objet. - Spread :
...valeurcôté envoi éclate un tableau ou un objet en ses éléments individuels.
C'est tout le modèle mental à retenir. Le reste de cette page, ce sont juste des exemples concrets de chacun, et les patterns que tu vas réutiliser en boucle.
Les paramètres rest en JavaScript : regrouper les arguments
Un paramètre rest dans la signature d'une fonction collecte n'importe quel nombre d'arguments dans un vrai tableau :
nums est un tableau tout ce qu'il y a de plus classique. Tu peux le passer à .map, à .filter, regarder sa .length, le transmettre à une autre fonction — bref, tout ce qu'on fait d'habitude avec un tableau.
Les paramètres rest peuvent cohabiter avec des paramètres classiques, à condition que le paramètre rest soit toujours en dernière position :
label capte le premier argument ; tout ce qui suit atterrit dans items. Placer le paramètre rest ailleurs qu'en dernière position déclenche une erreur de syntaxe.
Rest vs l'ancien objet arguments
L'ancien code JavaScript s'appuie sur une variable un peu magique appelée arguments, disponible dans les fonctions classiques. Elle ressemble à un tableau, mais n'en est pas vraiment un : impossible donc d'y appliquer directement les méthodes de tableau. Les paramètres rest la remplacent sans effort :
Les fonctions fléchées n'ont même pas d'objet arguments : les paramètres rest sont donc le seul moyen d'y accepter un nombre variable d'arguments. Dans tout nouveau code, privilégie ...args.
L'opérateur spread dans les appels de fonction
Le spread fait exactement l'inverse : il prend un tableau et le décompose en arguments individuels au moment de l'appel.
Math.max attend des nombres individuels, pas un tableau. Avant le spread, il fallait écrire Math.max.apply(null, nums). Aujourd'hui, un simple ... suffit.
Remarquez bien : le même ... joue le rôle de rest dans la définition de la fonction et de spread dans l'appel — c'est sa position qui détermine son rôle.
Spread dans les littéraux de tableau
L'opérateur spread dans un littéral de tableau permet de copier ou de combiner des tableaux :
[...a] te donne un nouveau tableau avec les mêmes éléments — pratique quand tu veux trier ou modifier sans toucher à l'original :
scores reste intact puisque .sort s'est appliqué sur la copie. Petit réflexe, mais gros bénéfice quand tu écris du code qui ne doit pas provoquer d'effets de bord inattendus.
L'opérateur spread sur les objets en JavaScript
L'opérateur spread fonctionne aussi sur les objets classiques : il fusionne leurs propriétés dans un nouvel objet.
Ce sont les dernières clés qui l'emportent. updates.age écrase user.age, et city s'ajoute au passage. L'ordre des spreads détermine le résultat final — gardez bien ça en tête quand vous empilez des valeurs par défaut et des surcharges :
Les valeurs par défaut d'abord, les choix de l'utilisateur ensuite. C'est fontSize de l'utilisateur qui l'emporte, tandis que theme est hérité.
Le piège de la copie superficielle
L'opérateur spread copie sur un seul niveau. Les objets et tableaux imbriqués restent partagés entre l'original et la copie :
Les deux tableaux affichent le nouveau tag parce que copy.tags et original.tags pointent vers le même tableau. Le spread n'a pas cloné la liste imbriquée — il a juste recopié la référence.
Pour obtenir une vraie copie profonde de données simples, utilise plutôt structuredClone :
Les deux tableaux sont désormais indépendants. structuredClone est disponible nativement dans les navigateurs modernes et dans Node, gère les structures imbriquées, et c'est la bonne solution dès que le clonage superficiel ne suffit plus.
Les paramètres rest dans la déstructuration
L'opérateur rest fonctionne aussi en déstructuration : il récupère tous les éléments ou propriétés restants.
Extraire quelques champs et regrouper le reste dans un seul objet : c'est un grand classique quand on transmet des props, qu'on retire des champs sensibles ou qu'on prépare une version modifiée de données :
password est extrait (puis ignoré) ; safe récupère tout le reste. Aucune mutation, aucune copie manuelle.
Récapitulatif rapide
...nomdans une liste de paramètres ou un pattern de destructuration, c'est rest : ça collecte....valeurdans un appel de fonction, un littéral de tableau ou un littéral d'objet, c'est spread : ça étale.- Les copies avec spread sont superficielles. Les structures imbriquées restent partagées. Pour une copie en profondeur, passe par
structuredClone. - Les paramètres rest sont de vrais tableaux — utilise-les à la place de
arguments. - Dans un littéral d'objet, les spreads placés plus loin écrasent ceux d'avant : c'est comme ça qu'on construit un système de valeurs par défaut avec surcharge.
La suite : les closures
En JavaScript, les fonctions ne se contentent pas de prendre des arguments et de renvoyer un résultat — elles mémorisent aussi la portée dans laquelle elles ont été définies. Cette mémoire s'appelle une closure, et c'est le mécanisme qui se cache derrière les callbacks, les factories et la plupart des patterns que tu vas croiser dans la page suivante.
Questions fréquentes
Quelle est la différence entre rest et spread en JavaScript ?
Les deux utilisent la même syntaxe ... mais font exactement l'inverse. Rest regroupe plusieurs valeurs dans un seul tableau — on le retrouve dans la liste des paramètres d'une fonction et dans la déstructuration. Spread étale un itérable ou un objet en ses éléments — on le retrouve dans les appels de fonctions, les tableaux et les objets littéraux. Retiens cette règle : si ... est du côté qui reçoit, c'est rest ; s'il est du côté qui donne, c'est spread.
Comment fonctionnent les paramètres rest dans une fonction ?
Un paramètre rest comme function sum(...nums) regroupe tous les arguments passés à la fonction dans un vrai tableau appelé nums. Il doit obligatoirement être le dernier paramètre de la liste. Contrairement à l'ancien objet arguments, un paramètre rest est un vrai Array, donc .map, .filter et .reduce fonctionnent directement dessus, sans bidouillage.
L'opérateur spread fait-il une copie profonde ?
Non. Spread ne copie qu'un seul niveau — c'est une copie superficielle (shallow copy). { ...user } te donne un nouvel objet avec les mêmes clés de premier niveau, mais les objets et tableaux imbriqués restent des références partagées. Pour une copie profonde, utilise structuredClone(value), ou passe par JSON.parse(JSON.stringify(...)) pour des données simples.