Valeur vs Référence

Primitifs, Objets, Shallow & Deep Clone

Utilisez les flĂšches, cliquez ou glissez pour naviguer

Objectifs de la leçon

1. Primitifs = copie par valeur

Chaque variable a sa propre valeur

2. Objets = copie par référence

Plusieurs variables pointent vers le mĂȘme objet

3. Identifier les bugs de mutation

Modifier une "copie" qui modifie l'original

4. Shallow clone (spread, assign)

Copier le premier niveau seulement

5. Deep clone (structuredClone)

Copier en profondeur tous les niveaux

Plan du cours

1

Le piÚge n°1 : const copie = original

Pourquoi ça ne copie PAS l'objet

2

Primitifs vs Objets

L'analogie de la maison et de l'adresse

3

Démo live : mutation involontaire

Modifier une copie qui modifie aussi l'original

4

Shallow clone : spread & Object.assign

La solution... mais avec un piĂšge!

5

Deep clone : structuredClone()

La solution moderne et complĂšte

Le piÚge n°1 en JS

const copie = original

ne copie PAS l'objet!

Ça copie juste la rĂ©fĂ©rence (l'adresse)

Le problĂšme concret

const original = { nom: 'Alice' };

const copie = original;

copie.nom = 'Bob';

console.log(original.nom);

// 'Bob' !!!

On a modifié l'original sans le vouloir!

C'est le bug le plus courant en JavaScript

Primitifs vs Objets

La différence fondamentale

Primitifs

Copie par valeur

Objets

Copie par référence

Les types primitifs

Copie par valeur = chaque variable a sa propre copie

string

'hello'

number

42, 3.14

boolean

true, false

null

absence de valeur

undefined

non défini

symbol

identifiant unique

let a = 5;

let b = a; // b reçoit une COPIE de la valeur

b = 10;

console.log(a); // 5 (inchangé!)

Les objets (et tableaux!)

Copie par rĂ©fĂ©rence = plusieurs variables pointent vers le MÊME objet

object

{ nom: 'Alice' }

array

[1, 2, 3]

const arr1 = [1, 2, 3];

const arr2 = arr1; // arr2 pointe vers le MÊME tableau!

arr2.push(4);

console.log(arr1); // [1, 2, 3, 4] (modifié!)

L'analogie de la maison

Primitif

Tu écris l'adresse sur un papier

Tu copies le papier

Chaque papier a SA propre adresse

Objet

La variable = une adresse

Tu copies l'adresse

Les deux pointent vers la MÊME maison

Si tu peins la maison en rouge depuis l'adresse A...

La maison est aussi rouge depuis l'adresse B!

C'est la MÊME maison, pas deux maisons identiques

Visualisation

Primitifs

let a = 5;

let b = a;

a

5

b

5

Deux boßtes séparées

Objets

const a = { x: 5 };

const b = a;

a

adr: 0x1

b

adr: 0x1

->

Objet

{ x: 5 }

Deux rĂ©fĂ©rences vers le MÊME objet

Démo Live

Modifier une "copie" modifie l'original

Le bug qui fait perdre des heures de debug

Exemple : Le bug classique

const user = {

nom: 'Alice',

age: 25

};

function anniversaire(personne) {

personne.age++;

return personne;

}

const nouveau = anniversaire(user);

console.log(user.age); // 26 (modifié!)

console.log(nouveau.age); // 26 (mĂȘme objet!)

La fonction a modifié l'objet original!

C'est souvent involontaire et source de bugs

=== compare les références, pas le contenu

const a = { x: 1 };

const b = { x: 1 };

console.log(a === b);

false

Deux objets diffĂ©rents en mĂ©moire, mĂȘme s'ils ont le mĂȘme contenu!

const c = a;

console.log(a === c); // true (mĂȘme rĂ©fĂ©rence)

Shallow Clone

Copier le premier niveau

{ ...obj }

Spread operator

Object.assign()

Méthode classique

Le spread operator { ...obj }

CrĂ©e un NOUVEL objet avec les mĂȘmes propriĂ©tĂ©s

const original = { nom: 'Alice', age: 25 };

const copie = { ...original };

copie.nom = 'Bob';

console.log(original.nom); // 'Alice' (inchangé!)

console.log(copie.nom); // 'Bob'

Ça marche! L'original est protĂ©gĂ©.

Object.assign() - L'alternative

const original = { nom: 'Alice' };

const copie = Object.assign({}, original);

Le premier argument {} est l'objet cible

Les propriétés de original sont copiées dedans

Préférez le spread { ...obj } - plus moderne et lisible

Shallow clone pour les tableaux

const original = [1, 2, 3];

const copie = [...original];

// ou

const copie2 = original.slice();

copie.push(4);

console.log(original); // [1, 2, 3] (inchangé)

console.log(copie); // [1, 2, 3, 4]

Le piĂšge du Shallow Clone

Les sous-objets restent partagés!

Shallow = superficiel

Ça ne copie que le premier niveau

Le problÚme avec les objets imbriqués

const user = {

nom: 'Alice',

adresse: { ville: 'Paris' }

};

const copie = { ...user };

copie.adresse.ville = 'Lyon';

console.log(user.adresse.ville);

// 'Lyon' !!! L'original est modifié!

L'objet adresse est TOUJOURS partagé!

Le spread ne copie que les propriétés du premier niveau

Pourquoi ça ne marche pas?

user

nom: 'Alice'

adresse: 0x2

copie

nom: 'Alice'

adresse: 0x2

->

Objet @0x2

ville: 'Paris'

Partagé!

Le spread copie la VALEUR de chaque propriété

Pour adresse, la valeur est une RÉFÉRENCE (0x2)

Donc les deux pointent vers le mĂȘme sous-objet!

Solution manuelle : spread imbriqué

const copie = {

...user,

adresse: { ...user.adresse }

};

Ça marche, mais...

Fastidieux si l'objet est profond

Erreur-prone si on oublie un niveau

Il existe une meilleure solution!

Deep Clone

Copier en profondeur tous les niveaux

structuredClone()

La solution moderne

structuredClone() - La solution moderne

Copie récursivement TOUS les niveaux

const user = {

nom: 'Alice',

adresse: {

ville: 'Paris',

pays: { nom: 'France' }

}

};

const copie = structuredClone(user);

copie.adresse.pays.nom = 'Espagne';

console.log(user.adresse.pays.nom);

// 'France' (inchangé!)

Avantages de structuredClone()

Fonctionne avec tous les niveaux

Pas besoin de spread imbriqué manuel

GĂšre les tableaux, Map, Set, Date...

Plus puissant que JSON.parse/stringify

Support navigateur moderne

Disponible dans tous les navigateurs récents

Ne fonctionne pas avec les fonctions

Les fonctions ne peuvent pas ĂȘtre clonĂ©es

Alternative : JSON.parse(JSON.stringify())

const copie = JSON.parse(JSON.stringify(user));

Inconvénients

Perd les fonctions

Perd les undefined

Perd les Symbol

Perd les références circulaires

Quand l'utiliser?

Données JSON simples

Compatibilité trÚs ancienne

Préférez structuredClone() - plus robuste!

PiÚges courants à éviter

Confusion const vs immuable

const obj = { x: 1 };

obj.x = 2; // OK! const n'empĂȘche PAS la mutation

obj = {}; // Erreur! const empĂȘche la rĂ©assignation

const = référence constante, pas objet immuable

Oublier que les tableaux sont des objets

const a = [1,2,3];

const b = a;

b.push(4); // a est aussi modifié!

Les tableaux ont le mĂȘme comportement que les objets

Résumé : Quand utiliser quoi?

Primitifs (string, number, boolean...)

Copie automatique par valeur - pas de souci!

Objet simple (1 niveau)

Utilise { ...obj } ou Object.assign()

Objet imbriqué (plusieurs niveaux)

Utilise structuredClone()

Jamais : copie = original

Ça ne crĂ©e PAS une copie, juste une autre rĂ©fĂ©rence!

À retenir!

Primitifs

Copie par valeur

Chaque variable = sa propre donnée

Objets

Copie par référence

Plusieurs variables = mĂȘme objet

Shallow

{ ...obj }

Premier niveau seulement

Deep

structuredClone()

Tous les niveaux

L'analogie de la maison est la plus efficace pour expliquer les références

Exercices pratiques

1. Prédire le résultat

Que vaut a aprĂšs: let a = 5; let b = a; b = 10; ?

2. Corriger le bug

Une fonction modifie l'objet original - utiliser le spread

3. Deep clone nécessaire

Créer une vraie copie d'un objet avec sous-objets

4. Identifier le piĂšge

Pourquoi ce code modifie-t-il l'original?

Questions?

C'est un concept difficile - prévoir du temps pour les exercices

Les bugs de mutation sont les plus difficiles à débugger

Mais maintenant vous savez les éviter!