-1

I have the following code:

const heroes = [
  { name: 'Wolverine',      family: 'Marvel',    isEvil: false },
  { name: 'Deadpool',       family: 'Marvel',    isEvil: false },
  { name: 'Magneto',        family: 'Marvel',    isEvil: true  },
  { name: 'Charles Xavier', family: 'Marvel',    isEvil: false },
  { name: 'Batman',         family: 'DC Comics', isEvil: false },
  { name: 'Harley Quinn',   family: 'DC Comics', isEvil: true  },
  { name: 'Legolas',        family: 'Tolkien',   isEvil: false },
  { name: 'Gandalf',        family: 'Tolkien',   isEvil: false },
  { name: 'Saruman',        family: 'Tolkien',   isEvil: true  }
]

var newHeroes = heroes.slice(0);

newHeroes[0] = { name: 'Test', family: '2', isEvil: false };
newHeroes[1].name = 'Test 2';

console.log(newHeroes);
console.log(heroes);

As soon as I'm slicing the first array, I expected the second to be a non-memory copy of the heroes const. So, whenever I change the newHeroes array, I thought that the first one wouldn't change.

When I change the entire content (like newHeroes[0] = Object), it works perfectly. This changes the second array only.

But when I try to change the property directly (newHeroes[1].name = 'Test 2'), it changes in both arrays.

Does anybody could explain me why?

Thank you! :-)

Guilherme Chiara
  • 1,154
  • 2
  • 12
  • 15

1 Answers1

1

You need to create a deep copy of your array since your array is composed of objects which in turn hold their own references. Slice will just create a shallow copy. You can do something like this:

const heroes = [
  { name: 'Wolverine',      family: 'Marvel',    isEvil: false },
  { name: 'Deadpool',       family: 'Marvel',    isEvil: false },
  { name: 'Magneto',        family: 'Marvel',    isEvil: true  },
  { name: 'Charles Xavier', family: 'Marvel',    isEvil: false },
  { name: 'Batman',         family: 'DC Comics', isEvil: false },
  { name: 'Harley Quinn',   family: 'DC Comics', isEvil: true  },
  { name: 'Legolas',        family: 'Tolkien',   isEvil: false },
  { name: 'Gandalf',        family: 'Tolkien',   isEvil: false },
  { name: 'Saruman',        family: 'Tolkien',   isEvil: true  }
]

var newHeroes = heroes.reduce((newArr, hero) => {
  newArr.push({...hero}); // creating a shallow copy of this object
  return newArr;
}, [])

newHeroes[0] = { name: 'Test', family: '2', isEvil: false };
newHeroes[1].name = 'Test 2';

console.log(newHeroes);
console.log(heroes);
Steven Scaffidi
  • 2,280
  • 1
  • 12
  • 14
  • This will only solve the problem with array of shallow objects. If any object has a nested object, this method will fail. A recursive solution is required in order to make a deep copy. – Boris Lobanov Feb 19 '18 at 22:04
  • Yea that's correct (note I put a comment that said that this is a shallow copy of the object). I was just answering his use case. There are a million stack-overflow answers for creating deep copies. This is sufficient for this use case though. – Steven Scaffidi Feb 19 '18 at 22:06