DEV Community

Cover image for Object Assign and Spread Operator: Why they can be villains?
Olavio Lacerda
Olavio Lacerda

Posted on • Updated on

Object Assign and Spread Operator: Why they can be villains?

First, let's understand what each of them does:

Object Assign

According to MDN Web Docs, the Object.assign() method:

copies all enumerable own properties from one or more source objects to a target object. It returns the target object

Which in simple words: you can copy values from objects into a new object.

const person = {
  name: {
    first: "Dolly",
    last: "Guarana",
  },
  age: 30,
};

const clonedByAssign = Object.assign({}, person);
// Object { name: { first: "Dolly", last: "Guarana", }, age: 30 }
Enter fullscreen mode Exit fullscreen mode

Spread Operator

The same situation goes when using Spread Operator, as we can see in MDN Web Docs).

It copies the own enumerable properties from a provided object onto a new object.

So, the Spread Operator makes the same thing as Object.assign() creating a shallow clone, when properties inside the objects are just references to other objects.

const person = {
  name: {
    first: "Dolly",
    last: "Guarana",
  },
  age: 30,
};

const clonedBySpread = { ...person };
// Object { name: { first: "Dolly", last: "Guarana", }, age: 30 }
Enter fullscreen mode Exit fullscreen mode

The problem 😟

When we are dealing with an object and we want to copy nested properties inside, we need to do a deep clone. Using Object.assign() or Spread Operator, the deep clone action could be a problem and probably your worst villain!

Let's see an example:

// Create a simple object with some nested properties
const person = {
  name: {
    first: "Dolly",
    last: "Guarana",
  },
  age: 30,
};

// Clone the person object to save its properties
const clonedByObjectAssign = Object.assign({}, person);
const clonedBySpread = { ...person };

console.log(`Original person: ${JSON.stringify(person)}`);
// Object { name: { first: "Dolly", last: "Guarana" }, age: 30 };

// Change the value of the person properties
person.name.last = "Cola";
person.age = 15;

console.log(person.age); // 15
// Expected to be 30 (it's a clone from the person object before the changes)
console.log(clonedBySpread.age ); // 30
console.log(clonedByObjectAssign.age); // 30

console.log(person.name.last ); // Cola
// Expected to be `Guarana` (it's a clone from the person object before the changes)
console.log(clonedBySpread.name.last ); // Cola
console.log(clonedByObjectAssign.name.last); // Cola
Enter fullscreen mode Exit fullscreen mode

But why? 🤔

Well, when we clone an object literals using Object.assign() or spread operator, it only copies property values. If the source value is a reference to another object only its reference value will be copied and this could bring memory sharing problems.

The object within the name property is only a reference to another object, so when you copy it you'll be copying that reference.

If at someplace on your code the referenced object changes its properties, you'll receive a new object with unexpected values because you'll be using the same memory reference to that object, and possibly it'll make you crazy for hours until realizes it.

The solution 😎

So, to avoid that problem we have some packages to do that manipulation for us, I'll show you the clone method available at Ramda package, but there's a lot of other ways to do that.

Lets clone the same object, but now using Ramda:

const R = require('ramda');

const clonedByRamda = R.clone(person);

console.log(person.age); //15
console.log(clonedByRamda.age); // 30

console.log(person.name.last); // Cola
console.log(clonedByRamda.name.last); // Guarana
Enter fullscreen mode Exit fullscreen mode

See it? Now the cloned object remained intact even with the modifications on the original object.

Conclusion

Always care about the packages, libs or functions that you're using, they can be far more complicated than they look like, giving you unexpected behaviours on simple things.

And that's it, more details you can check in the links below, hope you liked, that was my first post and I'd be very happy if you comment and share with your friends 🙂

Best wishes and may the Force be with you

References

Lodash(another way to do the clone): https://lodash.com/docs/4.17.15#cloneDeep
Ramda: https://ramdajs.com
Tips from my coworker and friend: https://github.com/arielril
Great examples: https://stackoverflow.com/questions/4459928/how-to-deep-clone-in-javascript
Mozilla Developer: https://developer.mozilla.org/pt-BR/docs/Web/JavaScript/Reference

Top comments (0)