web-dev-qa-db-fra.com

Comment copier en profondeur un objet personnalisé en JavaScript?

Je surfe ici depuis un moment et je n'ai toujours pas trouvé de réponse qui fonctionne pour moi.

Existe-t-il un moyen de copier en profondeur un objet non-brut dans JS?

J'ai essayé jQuery.extend(true, {}, this) mais il n'en a cloné qu'une partie, le reste est resté en tant que référence à un autre objet.

7
Robmeister2015

Voici 3 méthodes différentes pour copier des objets. Chaque méthode a ses avantages et ses inconvénients, alors lisez et choisissez ce qui convient le mieux à votre situation.

Méthode Object.assign

Utilisez Object.assign, qui "est utilisé pour copier les valeurs de toutes les propriétés propres énumérables d'un ou de plusieurs objets source vers un objet cible". Ceci copie les valeurs et les fonctions. Au moment de la rédaction de cet article, la prise en charge du navigateur est bonne mais n'est pas parfaite, mais il s'agit de la meilleure méthode IMO des trois.

const obj1 = {a:1, b:2};
const obj1Copy = Object.assign(obj1)

Méthode d'opérateur Spread

Alternativement, vous pouvez utiliser le spread operator pour passer d'un objet à un autre. Gardez à l'esprit que cela copiera les valeurs des clés, mais si vous la valeur d'une clé est une adresse mémoire (un autre objet imbriqué ou un tableau), il s'agira uniquement d'une copie superficielle.

const obj1 = {a: () => {}, b:2}
const obj1Copy = { ...obj1 }

JSON stringify/parse astuce

Si l'objet n'a pas de références circulaires ou de fonctions en tant que valeurs, vous pouvez utiliser l'astuce de json stringify:

let myCopy = JSON.parse(JSON.stringify(myObject));

Aucune bibliothèque requise et fonctionne très bien pour la plupart des objets.

10
Michael Jasper

Vous pouvez utiliser la fonction cloneDeep de lodash - https://lodash.com/docs/4.16.4#cloneDeep

Exemple (de docs)

var objects = [{ 'a': 1 }, { 'b': 2 }];

var deep = _.cloneDeep(objects);
console.log(deep[0] === objects[0]);
// => false
4
Felipe Sabino

Si vous avez affaire à une instance de classe, vous pouvez utiliser quelque chose comme ceci.

Vous n'avez pas besoin de copier les fonctions car elles sont déléguées sur le prototype.

// myObject constructor
function myObject(foo, bar){
  this.foo = foo
  this.bar = bar
}
// delegate the functions to a prototype
myObject.prototype.something = function(){
  console.log('something')
}

function instanceCopy(obj) {
  // copy the object by the constructor
  const copy = new obj.constructor()
  const keys = Object.keys(obj)
  keys.forEach(key => {
    copy[key] = obj[key]
  })
  return copy
}

const myObj = new myObject('foo', 'bar')
const copyObj = instanceCopy(myObj)

console.log('myObj', myObj)
console.log('copyObj', copyObj)
console.log('same ?', copyObj === myObj)

// can we still call the functions
copyObj.something()
<script src="https://codepen.io/synthet1c/pen/WrQapG.js"></script>
0
synthet1c