Object Assign and Spread Operator: Why they can be villains?
Tags: javascript, typescript, spreadoperator, objectassign
Published: 2020-08-09 21:54:35

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

## Object Assign 

According to [MDN Web Docs](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign), 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. 
</br>
```js
const person = {
  name: {
    first: "Dolly",
    last: "Guarana",
  },
  age: 30,
};

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

## Spread Operator

The same situation goes when using `Spread Operator`, as we can see in [MDN Web Docs](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_syntax)). 

>  *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.
</br>
```js
const person = {
  name: {
    first: "Dolly",
    last: "Guarana",
  },
  age: 30,
};

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

## 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:
</br>
```js
// 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
```

### 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](https://ramdajs.com/docs/#clone) package, but there's a lot of other ways to do that.

Lets clone the same object, but now using `Ramda`:
</br>
```js
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
```
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