Object References and Copying in JavaScript

vaishnavi pandey
Last Updated: May 13, 2022

Introduction

JavaScript is based on a fundamental object-oriented paradigm. Objects in JavaScript, like items in many other programming languages, can be compared to real-world objects. 


An object in JavaScript is a self-contained entity with attributes and a type. Consider a car as an example. A car is a physical object with qualities. A car has a colour, a pattern, a weight, a material made of, and so on. JavaScript objects, too, can have properties that determine their traits.


There are times when we need to clone or copy an object in JavaScript. Copying an object is a confusing task. In this article, we will discuss this referencing of objects.


Let us discuss the various ways of copying an object.

Shallow and Deep Copy

While copying objects in JavaScript, we often get confused between deep copy and shallow copy. So, without making it more complex, we’ll explain this with the help of an example.

 

Let’s assume A and B are objects. If A is assigned to B, when changing the value of A, check to see if the value of B changes. 

 

  • If B changes along with A, it suggests that B is a shallow copy of A. 
     
  • If B does not change, it is a deep copy of A.


Deep copy and shallow copy are primarily used for the reference data type parameter. A shallow copy means copying only the reference address, while a deep copy entails cloning the object.

The Basic Approach

You must be thinking that why can’t we simply use the (=) operator to copy the objects? 

Well, we’ll show you why.

 

Objects in JavaScript are reference types. And reference types don't hold values, they are a pointer to the value in memory. 

 

When we try to copy the object with the help of the assign(=) operator, we don’t create a new object. The assignment operator simply assigns the address of the previous object to a new variable.

 

Let us look at one example:

let obj={
   Name:'Vaishnavi',
   Id:'BTBT201813'};
   
let obj2=obj;

console.log(obj);
console.log(obj2);

obj2.Id='BTBT201810';

console.log(obj);
console.log(obj2);

Output:

{ Name: 'Vaishnavi', Id: 'BTBT201813' }
{ Name: 'Vaishnavi', Id: 'BTBT201813' }
{ Name: 'Vaishnavi', Id: 'BTBT201810' }
{ Name: 'Vaishnavi', Id: 'BTBT201810' }

Explanation:

In the above example, we can clearly see that if we make any change in the first object, it gets reflected in the new object as well. This is because both the objects are referencing the same memory location. To solve this problem, JavaScript provides a variety of ways. 

 

Some important methods to achieve this are given below, along with their problems and solutions.

Using Methods

To copy an object in JavaScript, we have three significant options. Let’s see them one by one.

1.) The Object.assign Method

The Object.assign() method copies all the properties from one or more source objects to a target object. It returns the modified target object. This method will help us fix the problem we saw in the basic approach given above.


Syntax: Object.assign(target, ...sources)

Let’s understand with the help of an example.

let obj={
    Name:'Vaishnavi'
}

let obj2 = Object.assign({},obj)

console.log(obj);
console.log(obj2);

obj2.Name='Shubhi';

console.log(obj);
console.log(obj2);

Output:

{ Name: 'Vaishnavi' }
{ Name: 'Vaishnavi' }
{ Name: 'Vaishnavi' }
{ Name: 'Shubhi' }


This thing can also be achieved by using the spread operator, let’s see how.

2.) The Spread Operator

We can perform object copying by using the spread operator introduced in ES6. Let’s see with the help of an example.

let obj={
   Name:'Vaishnavi'}

let obj2 = { ...obj}

console.log(obj);
console.log(obj2);

obj2.Name='Shubhi';


console.log(obj);
console.log(obj2);

Output:

{ Name: 'Vaishnavi' }
{ Name: 'Vaishnavi' }
{ Name: 'Vaishnavi' }
{ Name: 'Shubhi' }


But, this is definitely not the full proof solution, because the moment we start getting a nested object inside our first object, this will not work.

Let’s see how.

let obj={
   Name:'Vaishnavi',
   Skills: {Primary: 'JavaScript', Secondary: 'Android'}
}
let obj2 = { ...obj}
console.log(obj);
console.log(obj2);

obj2.Name='Shubhi';
obj2.Skills.Primary='Full Stack';

console.log(obj);
console.log(obj2);

Output:

{ Name: 'Vaishnavi',
 Skills: { Primary: 'JavaScript', Secondary: 'Android' } }
{ Name: 'Vaishnavi',
 Skills: { Primary: 'JavaScript', Secondary: 'Android' } }
{ Name: 'Vaishnavi',
 Skills: { Primary: 'Full Stack', Secondary: 'Android' } }
{ Name: 'Shubhi',
 Skills: { Primary: 'Full Stack', Secondary: 'Android' } }

Explanation:

We can clearly see that we changed the primary skill of object 2 in the above code and this change got reflected in object 1 as well.


So, we noticed that the above two methods made a partial deep copy of the objects. To make sure that the changes in the objects happen independently, here’s a different method. 

3.) The JSON.parse and stringify Method

We can use the JSON’s parse method along with stringify method to fix the problem above. Let’s see with the help of an example.

Example:

let obj={
   Name:'Vaishnavi',
   Skills: {Primary: 'JavaScript', Secondary: 'Android'}
}
let obj2 = JSON.parse(JSON.stringify(obj));
console.log(obj);
console.log(obj2);

obj2.Name='Shubhi';
obj2.Skills.Primary='Full Stack';

console.log(obj);
console.log(obj2);

Output:

{ Name: 'Vaishnavi',
 Skills: { Primary: 'JavaScript', Secondary: 'Android' } }
{ Name: 'Vaishnavi',
 Skills: { Primary: 'JavaScript', Secondary: 'Android' } }
{ Name: 'Vaishnavi',
 Skills: { Primary: 'JavaScript', Secondary: 'Android' } }
{ Name: 'Shubhi',
 Skills: { Primary: 'Full Stack', Secondary: 'Android' } }
 

Explanation:

So, in the above example, we are actually stringifying the first object into a JSON string and then again parsing that JSON string and creating another object from it? So, this is an example of deep cloning.


But, this method works absolutely fine until and unless we introduce some function in the object. Let’s see how.

Example:

let obj={
   Name:'Vaishnavi',
   Skills: {Primary: 'JavaScript', Secondary: 'Android'},
   calculateAge: function(params){
       return 20;
   },
   joiningDate: new Date()
}
let obj2 = JSON.parse(JSON.stringify(obj));
console.log(obj);
console.log(obj2);
obj2.Name='Shubhi';
obj2.Skills.Primary='Full Stack';
console.log(obj);
console.log("The type of JoiningDate in object 1 is: "+ typeof(obj.joiningDate));
console.log(obj2);
console.log("The type of JoiningDate in object 2 is: "+ typeof(obj2.joiningDate));

Output:

{ Name: 'Vaishnavi',
 Skills: { Primary: 'JavaScript', Secondary: 'Android' },
 calculateAge: [Function: calculateAge],
 joiningDate: 2021-11-29T07:54:50.236Z }
{ Name: 'Vaishnavi',
 Skills: { Primary: 'JavaScript', Secondary: 'Android' },
 joiningDate: '2021-11-29T07:54:50.236Z' }
{ Name: 'Vaishnavi',
 Skills: { Primary: 'JavaScript', Secondary: 'Android' },
 calculateAge: [Function: calculateAge],
 joiningDate: 2021-11-29T07:54:50.236Z }
The type of JoiningDate in object 1 is: object
{ Name: 'Shubhi',
 Skills: { Primary: 'Full Stack', Secondary: 'Android' },
 joiningDate: '2021-11-29T07:54:50.236Z' }
The type of JoiningDate in object 2 is: string
 

Explanation:

  • In the output, we can see that the method calculateAge, that we mentioned in object 1 is totally missing from object 2.

 

  • One more thing to notice is that the joiningDate is no more a date object in object 2, it became a string object. This means that for certain ‘types’ the original type is lost when we use JSON parse and stringify method.


So, in order to overcome these two problems, we’ve to find a better solution. 

Using a Third-Party Library

We can use some amazing third party libraries to perform deep copies of objects in JavaScript. One such library is lodash. We have to install it and import it into our program.


Once we’ve included that library, let’s see how do we create a deep copy.

 

Example:

const low_dash = require('lodash.deepCopy')
let obj={
   Name:'Vaishnavi',
   Skills: {Primary: 'JavaScript', Secondary: 'Android'},
   calculateAge: function(params){
       return 20;
   },
   joiningDate: new Date()
}
let obj2 = low_dash.cloneDeep(obj);
console.log(obj);
console.log(obj2);

obj2.Name='Shubhi';
obj2.Skills.Primary='Full Stack';

console.log(obj);
console.log("The type of JoiningDate in object 1 is: "+ typeof(obj.joiningDate));
console.log(obj2);
console.log("The type of JoiningDate in object 2 is: "+ typeof(obj2.joiningDate));

Output:

{
 Name: 'Vaishnavi',
 Skills: { Primary: 'JavaScript', Secondary: 'Android' },
 calculateAge: [Function: calculateAge],
 joiningDate: 2021-11-29T11:20:07.692Z
}
{
 Name: 'Vaishnavi',
 Skills: { Primary: 'JavaScript', Secondary: 'Android' },
 calculateAge: [Function: calculateAge],
 joiningDate: 2021-11-29T11:20:07.692Z
}
{
 Name: 'Vaishnavi',
 Skills: { Primary: 'JavaScript', Secondary: 'Android' },
 calculateAge: [Function: calculateAge],
 joiningDate: 2021-11-29T11:20:07.692Z
}
The type of JoiningDate in object 1 is: object
{
 Name: 'Shubhi',
 Skills: { Primary: 'Full Stack', Secondary: 'Android' },
 calculateAge: [Function: calculateAge],
 joiningDate: 2021-11-29T11:20:07.692Z
}
The type of JoiningDate in object 2 is: object


Now, we can see that a genuine deep copy of the object has been created. And all the types have been secured. This was all about creating copies of objects in JavaScript. Let’s see some of the frequently asked questions on this topic.

Frequently Asked Questions

1.) What is a fatal copy in JS?

Answer: In this type of copy, no new objects are created we just point to the source object. It is achieved by the assignment operator.

 

2.) What is a shallow copy in JS?

Answer: In this copy method, we create a copy of the object but we don’t create a separate copy of the Inner object. so when changes are made on any of the source or target objects then changes are reflected in both of them. It is achieved by the assign() method.

 

3.) What is a deep copy in JS?

Answer: In this copy method, we get rid of the problem of the shallow copy and we create a separate copy of the inner object as well so when we make changes on any of the source or target objects then it is reflected on the other object 

Key Takeaways

In this blog, we discussed how objects are copied in JavaScript. We’ve seen various approaches to making shallow and deep copies of objects. We’ve also introduced one third party library to do so.

 

You can use CodeStudio to practise questions on web development and use the Coding Ninja Self-paced Web development to grasp numerous web development concepts.

 

Happy Learning!

 

Was this article helpful ?
0 upvotes

Comments

No comments yet

Be the first to share what you think