Copie approfondie dans ES6 en utilisant le signe de diffusion

J’essaie de créer une méthode de copie en profondeur pour mon projet Redux qui fonctionnera avec des objects plutôt qu’avec des tableaux. J’ai lu que dans Redux, chaque état ne devrait rien changer aux états précédents.

export const mapCopy = (object, callback) => { return Object.keys(object).reduce(function (output, key) { output[key] = callback.call(this, {...object[key]}); return output; }, {}); } 

Ça marche:

  return mapCopy(state, e => { if (e.id === action.id) { e.title = 'new item'; } return e; }) 

Cependant, il ne copie pas en profondeur les éléments internes, je dois donc les modifier pour:

 export const mapCopy = (object, callback) => { return Object.keys(object).reduce(function (output, key) { let newObject = {...object[key]}; newObject.style = {...newObject.style}; newObject.data = {...newObject.data}; output[key] = callback.call(this, newObject); return output; }, {}); } 

Ceci est moins élégant car il faut savoir quels objects sont passés. Y a-t-il un moyen dans ES6 d’utiliser le signe de diffusion pour copier un object en profondeur?

Aucune fonctionnalité de ce type n’est intégrée à ES6. Je pense que vous avez quelques options en fonction de ce que vous voulez faire.

Si vous voulez vraiment copier profondément:

  1. Utilisez une bibliothèque. Par exemple, lodash a une méthode cloneDeep .
  2. Implémentez votre propre fonction de clonage.

Solution alternative à votre problème spécifique (pas de copie en profondeur)

Cependant, je pense que si vous voulez changer quelques choses, vous pouvez vous épargner du travail. Je suppose que vous contrôlez tous les sites d’appels à votre fonction.

  1. Indiquez que tous les rappels passés à mapCopy doivent renvoyer de nouveaux objects au lieu de muter l’object existant. Par exemple:

     mapCopy(state, e => { if (e.id === action.id) { return Object.assign({}, e, { title: 'new item' }); } else { return e; } }); 

    Cela utilise Object.assign pour créer un nouvel object, définit les propriétés de e sur ce nouvel object, puis définit un nouveau titre sur ce nouvel object. Cela signifie que vous ne modifiez jamais les objects existants et que vous en créez de nouveaux uniquement lorsque cela est nécessaire.

  2. mapCopy peut être très simple maintenant:

     export const mapCopy = (object, callback) => { return Object.keys(object).reduce(function (output, key) { output[key] = callback.call(this, object[key]); return output; }, {}); } 

Essentiellement, mapCopy fait confiance à ses appelants. C’est pourquoi j’ai dit que cela suppose que vous contrôliez tous les sites d’appels.

Au lieu de cela, utilisez ceci pour une copie profonde

 var newObject = JSON.parse(JSON.ssortingngify(oldObject)) 
 var oldObject = { name: 'A', address: { street: 'Station Road', city: 'Pune' } } var newObject = JSON.parse(JSON.ssortingngify(oldObject)); newObject.address.city = 'Delhi'; console.log('newObject'); console.log(newObject); console.log('oldObject'); console.log(oldObject); 

De MDN

Remarque: la syntaxe Spread va jusqu’à un niveau lorsque vous copiez un tableau. Par conséquent, cela peut ne pas convenir à la copie de tableaux multidimensionnels, comme le montre l’exemple suivant (c’est la même chose avec Object.assign () et la syntaxe de diffusion).

Personnellement, je suggère d’utiliser la fonction cloneDeep de Lodash pour le clonage multi-niveau object / tableau.

Voici un exemple de travail:

 const arr1 = [{ 'a': 1 }]; const arr2 = [...arr1]; const arr3 = _.clone(arr1); const arr4 = arr1.slice(); const arr5 = _.cloneDeep(arr1); const arr6 = [...{...arr1}]; // a bit ugly syntax but it is working! // first level console.log(arr1 === arr2); // false console.log(arr1 === arr3); // false console.log(arr1 === arr4); // false console.log(arr1 === arr5); // false console.log(arr1 === arr6); // false // second level console.log(arr1[0] === arr2[0]); // true console.log(arr1[0] === arr3[0]); // true console.log(arr1[0] === arr4[0]); // true console.log(arr1[0] === arr5[0]); // false console.log(arr1[0] === arr6[0]); // false