9

I have method:

export const groupActivities = ({ activities, tags, images, tickets }) => {
  if (!activities || !tags) {
    console.error('Must have activities and tags');
  }

  const groupActivities = Object.assign({}, activities);

  const groups = groupByTags({ activities: groupActivities, tags });

  groups.forEach(group => {
    group.length = group.activities.length;
    console.log(group.length);
    group.activities.forEach(activity => {
      if (images) {
        activity.images = activity.imageIds.map(id => images[id]);
      }

      if (tickets) {
        console.warn('No tickets provided to the groupactivities helper. May cause problems.');
        activity.tickets = activity.ticketIds.map(id => tickets[id]);
      }
    });
  });

  return groups;
};

Object.assign is copying the activities object, but still keeps references to it, so if I find a specific activity and change some property on it, it changes the original too! (changing groupActivities['someID'].name = 'name' changes the corresponding activity on activities object!)

This is causing some weird bugs. Any solution?

Using babel 5 for compiling.

Felix Kling
  • 795,719
  • 175
  • 1,089
  • 1,143
Mohamed El Mahallawy
  • 13,024
  • 13
  • 52
  • 84
  • 4
    Object.assign makes a shallow copy, so sub-object ref linking is to be expected. see about "cloning an object" to break the link. if you don't need inheritance, dates, or methods, `JSON.parse(JSON.stringify(obj))` can quickly copy plain objects without pesky external refs. – dandavis Dec 18 '15 at 03:25
  • 1
    *"Any solution?"* Make a deep copy? [What is the most efficient way to clone an object?](http://stackoverflow.com/q/122102/218196). – Felix Kling Dec 18 '15 at 03:28
  • Please read tag descriptions! [tag:babel] is for questions about the **Python** library with that name. – Felix Kling Dec 18 '15 at 03:28
  • i do need a deep copy, hence I thought `Object.assign` would do a deep copy? I am not using jquery, just es6 – Mohamed El Mahallawy Dec 18 '15 at 03:29
  • *"I thought `Object.assign` would do a deep copy"* It doesn't. What made you think that? *"I am not using jquery"* That's fine. – Felix Kling Dec 18 '15 at 03:29
  • @FelixKling I am seeing a number of answers suggestion `Object.assign` to do deep copy.... – Mohamed El Mahallawy Dec 18 '15 at 03:32
  • 1
    yeah well, regardless of what you've heard, you now have the correct answer. – dandavis Dec 18 '15 at 03:33
  • @MohamedElMahallawy: Can you link them, please? We can correct them then. – Bergi Dec 18 '15 at 03:57
  • i used lodash cloneDeep() for this – nick Aug 26 '20 at 10:26

1 Answers1

4

In fact this can be done in different ways:

  1. Implement you own if you don't want external import, but take in consideration nested object. I implemented my own as follow (in case you have a nested object you need deep clone, so set deep=true):
function cloneObj(obj, deep=false){
  var result = {};
  for(key in obj){
    if(deep && obj[key] instanceof Object){
       if(obj[key] instanceof Array){
         result[key] = [];
         obj[key].forEach(function(item){
            if(item instanceof Object){
               result[key].push(cloneObj(item, true));
            } else {
               result[key].push(item);
            }
         });
       } else {
         result[key] = cloneObj(obj[key]);
       }
    } else {
       result[key] = obj[key];
    }
  }
  return result
}


// Shallow copy
var newObject = cloneObj(oldObject);
// Deep copy
var newObject = cloneObj(oldObject, true);
  1. use jQuery:
// Shallow copy
var newObject = jQuery.extend({}, oldObject);

// Deep copy
var newObject = jQuery.extend(true, {}, oldObject);
  1. using UnderscoreJS:
 // Shallow copy
 var newObject = _.clone(oldObject);

PS: I tested my function with the following data and works fine:

var oldObject = {a:1, b:{d:2,c:6}, c:[1,2,{t:1}]};
newObject= cloneObj(oldObject, true);

newObject['b']['d']=8;
newObject['a']=8;
newObject['c'][2]['t']=5;


console.log(oldObject)
console.log(newObject)
Dhia
  • 10,119
  • 11
  • 58
  • 69