It is very important to understand how objects in javascript behave as it will help us avoiding unnecessary issues. Especially when using javascript frontend frameworks like REACT. Objects and data structures in javascript are considered to be mutable. This is because they passed by reference. First lets make sense of what did I mean by the above sentence
First lets make an object called person and a copy of that object and assign it to a variable.
const person = {name:'john', age: '25'}
const personCopy = person
So now What will happen if we change personCopy object.
personCopy.name = 'sam'
console.log(personCopy)
//Output: {name:'sam', age: '25'}
Well that is expected. What will happen if we print person ?
console.log(person)
//Output: {name:'sam', age: '25'}
Surprisingly the initial object has also changed. This is because in javascript objects are passed by reference therefore even though we assign it another variable it will still refer to the first object. It does not make a copy. This is not only for objects but also for arrays it will be the same case.
We have to take a copy of the initial object and then assign it to a new variable. There are several different solutions that can be used. But some of them won’t solve all your problems. Let’s take a look.
First method is performing a shallow copy. We can use the spread operator or Object.assign method to achieve it. It will copy all the properties and contents of that object By using the previous example,
const personCopy = {...person} //three dots is the spread operator
personCopy.name = 'sam'
console.log(personCopy)
//Output: {name:'sam', age: '25'}
console.log(person)
//Output: {name:'john', age: '25'}
As you can see now only the personCopy object is changed. We also can use Object.assign instead of spread operator.
const personCopy = Object.assign( {},person}
This will behave similarly as the spread operator. However there is an issue in this method. Let’s see what it is. Consider the example below.
const school = {
schoolName:'awesome school',
students: [‘john’,’sam’],
}
const newSchool = { ...school}
newSchool.schoolName = ‘new awesome school’
newSchool.students.push(‘peter’)
console.log(newSchool)
//Output: {schoolName:'new awesome school', //students://[‘john’,’sam’,’peter’],}
console.log(school)
//Output: {schoolName:'awesome school', students: //[‘john’,’sam’,’peter’],}
As you can see in the school object even though the schoolName is not change students array has been changed. This is because the spread operator/ Object.assign will only perform a shall copy. Which means only the first level of attributes will get copied if you have a nested object or an array in side it will still copy the reference of it.
The way to overcome this is to perform a deep copy. There are several ways we can do it. One way is using JSON.parse(JSON.stringify(school)) to create the copy. Even though this gets the job done, it is considered very performance intensive The most popular way of performing a deep copy is using deep clone method in lodash. Take a look at the example below.
//importing lodash in nodejs
const _ = require('lodash');
const newSchool =_.cloneDeep(school)
newSchool.schoolName = ‘new awesome school’
newSchool.students.push(‘peter’)
console.log(newSchool)
//Output: {schoolName:'new awesome school', students: [‘john’,’sam’,’peter’],}
console.log(school)
//Output: {schoolName:'awesome school', students: [‘john’,’sam’]}
In conclusion try to avoid mutating your objects and data structures in your javascript projects. This will help you to avoid unnecessary errors!! Hope you guys enjoyed this article