Menu
Français

Spread d'objet JavaScript : cloner, fusionner, écraser

Comment fonctionne le spread d'objet en JavaScript : cloner, fusionner, écraser des propriétés, et le piège de la copie superficielle qui surprend tout le monde.

Le spread operator en JavaScript : décomposer un objet dans un autre

La syntaxe de spread sur les objets — trois petits points devant un objet — recopie ses propriétés propres et énumérables dans l'objet littéral qui l'entoure. C'est le moyen le plus concis pour cloner un objet, fusionner deux objets ou produire une copie modifiée sans altérer l'original.

index.js
Output
Click Run to see the output here.

copy a les mêmes clés et valeurs que user, mais c'est bien un objet distinct. Modifier l'un n'affecte pas l'autre — en tout cas au premier niveau. On reviendra sur cette nuance juste après.

Le modèle mental à retenir : { ...obj } veut dire « déverse les propriétés de obj dans ce nouvel objet littéral ». Tout ce que tu écris à côté du spread vient s'ajouter au résultat.

Cloner un objet et écraser des propriétés en une seule étape

Le cas d'usage le plus courant du spread operator en JavaScript, c'est d'étaler un objet puis d'ajouter ou de remplacer quelques propriétés au passage. Les clés déclarées en dernier l'emportent : on commence donc par le spread, et on écrase ensuite :

index.js
Output
Click Run to see the output here.

user reste intact. updated est un nouvel objet dans lequel role a été remplacé. Ce pattern de mise à jour immuable, on le croise partout en JavaScript moderne : les updaters de state dans React, les reducers de Redux, bref, tout code qui évite la mutation en place.

Inversez l'ordre et vous obtenez le comportement inverse :

index.js
Output
Click Run to see the output here.

Ici, role: "guest" arrive en premier, donc user.role vient l'écraser. Pratique quand tu veux des valeurs par défaut que l'objet spreadé peut remplacer.

Fusionner deux objets en JavaScript

Pour fusionner plusieurs objets, il suffit de les étaler (spread) dans un nouveau littéral. En cas de clés en conflit, ce sont les objets placés en dernier qui l'emportent :

index.js
Output
Click Run to see the output here.

theme et fontSize viennent de userPrefs ; debug, lui, est hérité de defaults. Trois objets ? Quatre ? La règle ne change pas : on lit dans l'ordre, et c'est la dernière écriture qui l'emporte.

C'est l'équivalent moderne de Object.assign({}, defaults, userPrefs). Les deux font exactement la même chose, mais la version avec le spread se lit plus facilement et évite le piège classique du Object.assign(defaults, userPrefs) — qui, lui, modifie defaults directement.

Le spread fait une copie superficielle

C'est là que beaucoup se font avoir. Le spread ne copie que les propriétés de premier niveau d'un objet. Si la valeur d'une propriété est elle-même un objet ou un tableau, c'est la référence qui est copiée, pas le contenu.

index.js
Output
Click Run to see the output here.

Modifier copy.address.city a aussi modifié user.address.city — les deux objets pointent vers le même address. Le spread n'a créé qu'une nouvelle enveloppe externe : c'est ce qu'on appelle une copie superficielle en JavaScript.

Quand tu dois modifier une propriété imbriquée, applique le spread à chaque niveau que tu veux changer :

index.js
Output
Click Run to see the output here.

Pour un clone réellement profond de données arbitraires, tournez-vous vers structuredClone(obj). Cette fonction gère les objets imbriqués, les tableaux, les dates, les Map et les Set — et elle est intégrée nativement dans tous les runtimes modernes.

Spread vs rest en JavaScript

Les deux partagent les mêmes trois points, mais font exactement l'inverse. Le spread déploie ; le rest rassemble.

index.js
Output
Click Run to see the output here.

La règle simple à retenir : si les ... se trouvent avant un = (destructuration), c'est du rest. S'ils apparaissent dans un littéral d'objet ou de tableau après le =, c'est du spread.

Supprimer une propriété sans muter l'objet

En combinant la destructuration avec rest et le spread operator, on obtient une façon très propre de créer une copie d'un objet en retirant une clé — sans delete, sans mutation :

index.js
Output
Click Run to see the output here.

tempToken est extrait dans sa propre variable (que tu ignores), et tout le reste atterrit dans safe. L'objet user d'origine, lui, reste intact.

Ce que le spread ne copie pas

Quelques subtilités bonnes à connaître :

  • Les propriétés non énumérables ne sont pas copiées. La plupart des propriétés que tu crées sont énumérables par défaut, mais celles définies via Object.defineProperty et certaines propriétés natives ne le sont pas.
  • Le prototype n'est pas copié. { ...instance } te renvoie un objet simple, pas une instance de la classe d'origine. Les méthodes définies sur le prototype de la classe ne se retrouveront pas sur la copie.
  • Les getters sont évalués. Étaler un objet avec un getter déclenche ce getter une fois, et la valeur retournée est stockée comme une propriété classique sur le nouvel objet.
index.js
Output
Click Run to see the output here.

copy contient bien x et y, mais ça reste un simple objet — distance vit sur Point.prototype, et le spread n'y touche pas. Si tu dois cloner une instance de classe, c'est généralement à la classe elle-même de fournir sa propre méthode clone.

La suite : les méthodes de tableau

Le spread operator n'est qu'une pièce de la boîte à outils pour manipuler des données immuables. L'autre grosse pièce, ce sont les méthodes de tableau — map, filter, reduce et compagnie — qui renvoient de nouveaux tableaux au lieu de modifier ceux d'origine. On voit ça dans la page suivante.

Questions fréquentes

À quoi sert ...obj en JavaScript ?

À l'intérieur d'un littéral d'objet, ...obj recopie toutes les propriétés propres et énumérables de cet objet dans le nouvel objet. { ...user } crée donc un nouvel objet avec les mêmes clés et valeurs que user. C'est la façon standard de cloner ou de fusionner des objets sans toucher à l'original.

Comment fusionner deux objets en JavaScript ?

Il suffit de les spreader dans un nouveau littéral : const merged = { ...a, ...b }. Les propriétés de b écrasent celles de a quand les clés se chevauchent, car c'est toujours la dernière valeur qui gagne. Le résultat est le même qu'avec Object.assign({}, a, b), en plus lisible.

Le spread d'objet fait-il une copie profonde ?

Non. Le spread ne fait qu'une copie superficielle : il recopie les propriétés de premier niveau, mais les objets et tableaux imbriqués restent partagés par référence. Modifier copy.address.city modifiera aussi original.address.city. Pour une vraie copie profonde, utilise structuredClone(obj).

Quelle différence entre spread et rest ?

Ils s'écrivent pareil (...) mais font l'inverse l'un de l'autre. Le spread déploie un objet ou un tableau en propriétés ou éléments individuels : { ...user }. Le rest regroupe ce qui reste dans une seule variable : const { name, ...others } = user. C'est le contexte qui indique lequel des deux tu utilises.

Apprendre à coder avec Coddy

COMMENCER