Comment cloner en profondeur un objet JavaScript

JavaScript offre de nombreuses façons de copier un objet, mais toutes ne fournissent pas de copie complète. Apprenez la manière la plus efficace et découvrez également toutes les options dont vous disposez

La copie d'objets en JavaScript peut être délicate. Certaines méthodes effectuent une copie superficielle, ce qui est le comportement par défaut dans la plupart des cas.

Copie profonde vs copie peu profonde

Une copie superficielle copie avec succèstypes primitifscomme des nombres et des chaînes, mais toute référence d'objet ne sera pas copiée de manière récursive, mais à la place, le nouvel objet copié référencera le même objet.

Si un objet fait référence à d'autres objets, lors de l'exécution d'uncopie superficiellede l'objet, vouscopier les référencesaux objets externes.

Lors de l'exécution d'uncopie profonde, cellesles objets externes sont également copiés, le nouvel objet cloné est donc complètement indépendant de l'ancien.

En cherchant comment cloner en profondeur un objet en JavaScript sur Internet, vous trouverez de nombreuses réponses, mais les réponses sontpas toujours correct.

Option la plus simple: utilisez Lodash

Ma suggestion pour effectuer une copie profonde est de s'appuyer sur une bibliothèque bien testée, très populaire et soigneusement entretenue: Lodash.

Lodash offre le très pratiquecloneetdeepclonefonctions pour effectuer un clonage superficiel et profond.

Lodash a cette fonctionnalité intéressante:vous pouvez importer des fonctions individuelles séparémentdans votre projet pour réduire beaucoup la taille de la dépendance.

Dans Node.js:

const clone = require('lodash.clone')
const clonedeep = require('lodash.clonedeep')

Voici un exemple qui montre ces deux fonctions en cours d'utilisation:

const clone = require('lodash.clone')
const clonedeep = require('lodash.clonedeep')

const externalObject = { color: ‘red’, }

const original = { a: new Date(), b: NaN, c: new Function(), d: undefined, e: function () {}, f: Number, g: false, h: Infinity, i: externalObject, }

const cloned = clone(original)

externalObject.color = ‘blue’

console.info(‘⬇️ shallow cloning 🌈’) console.info( ‘✏️ Notice the i.color property we changed on original is also changed in the shallow copy’ ) console.log(original) console.log(cloned)

const deepcloned = clonedeep(original)

externalObject.color = ‘yellow’ console.log(’’) console.info(‘⬇️ deep cloning 🌈’) console.info(‘✏️ Notice the i.color property does not propagate any more’) console.log(original) console.log(deepcloned)

Dans cet exemple simple, nous créons d'abord une copie superficielle et éditons la propriété i.color, qui se propage à l'objet copié.

Dans le clone profond, cela ne se produit pas.

Object.assign ()

Object.assign()effectue une copie superficielle d'un objet, pas un clone profond.

const copied = Object.assign({}, original)

Étant une copie superficielle, les valeurs sont clonées et les références d'objets sont copiées (pas les objets eux-mêmes), donc si vous modifiez une propriété d'objet dans l'objet d'origine, elle est également modifiée dans l'objet copié, car l'objet interne référencé est le même:

const original = {
  name: 'Fiesta',
  car: {
    color: 'blue',
  },
}
const copied = Object.assign({}, original)

original.name = ‘Focus’ original.car.color = ‘yellow’

copied.name //Fiesta copied.car.color //yellow

Utilisation de l'opérateur de propagation d'objets

Leopérateur de propagationest unES6 / ES2015fonctionnalité qui fournit un moyen très pratique d'effectuer un clonage superficiel, équivalent à ce queObject.assign()Est-ce que.

const copied = { ...original }

Mauvaises solutions

En ligne, vous trouverez de nombreuses suggestions. Voici quelques faux:

Utiliser Object.create ()

Remarque: non recommandé

const copied = Object.create(original)

C'est faux, il n'effectue aucune copie.

Au lieu de cela, leoriginall'objet est utilisé commeprototypedecopied.

Apparemment ça marche, mais sous les capots ce n'est pas

const original = {
  name: 'Fiesta',
}
const copied = Object.create(original)
copied.name //Fiesta

original.hasOwnProperty('name') //true
copied.hasOwnProperty('name') //false

En savoir plus surObject.create().

Sérialisation JSON

Remarque: non recommandé

Certains recommandent de se transformer enJSON:

const cloned = JSON.parse(JSON.stringify(original))

mais cela a des conséquences inattendues.

En faisant cela, vousperdretoute propriété Javascript qui n'a pas de type équivalent dans JSON, commeFunctionouInfinity. Toute propriété attribuée àundefinedsera ignoré parJSON.stringify, les faisant manquer sur l'objet cloné.

De plus, certains objets sont convertis en chaînes, comme les objets Date par exemple (également, sans prendre en compte le fuseau horaire et par défaut à UTC), Set, Map et bien d'autres:

JSON.parse(
  JSON.stringify({
    a: new Date(),
    b: NaN,
    c: new Function(),
    d: undefined,
    e: function () {},
    f: Number,
    g: false,
    h: Infinity,
  })
)

Parsing as JSON

Cela ne fonctionne que si vous n'avez pas d'objets et de fonctions internes, mais uniquement des valeurs.

Téléchargez mon gratuitManuel du débutant JavaScript


Plus de tutoriels js: