DEV Community

Cover image for Object memory reference in JS
Akbar Ali
Akbar Ali

Posted on

Object memory reference in JS

const person1 = {
    name: "Alex",
    address: "Toronto"
}

const person2 = person1;
person2.name = "John";

console.log(person1);
Enter fullscreen mode Exit fullscreen mode

What would be the output of the above code?

Does that look like this:

{
    name: "Alex",
    address: "Toronto"
}
Enter fullscreen mode Exit fullscreen mode

You're wrong. It would look like this:

{
    name: "John",
    address: "Toronto"
}
Enter fullscreen mode Exit fullscreen mode

Yes, that's the correct output. But that was not what we ought to do. We need the name of the person1 to stay like whatever it was before. We changed the name of person2.

Then, where did it go wrong?

The problem is with the JavaScript's object memory reference. We only assigned the person1 variable to the person2 variable. Javascript keeps the memory reference of the variable in the place for both of them. That's why when we changed the name of person2, it affected person1.

How to overcome this bug?

Even, I had spent a full day debugging a commercial app and banged my keyboards due to frustration to find out it's just a memory reference bug.

Here's a solution:
Spread operator

const person1 = {
    name: "Alex",
    address: "Toronto"
}

const person2 = {...person1};
person2.name = "John";

console.log(person1);
Enter fullscreen mode Exit fullscreen mode

Here, we are spreading the person1 variable to create a new one. Now it would work fine as we expected. But, it has an exception.

What if our code was like this:

const person1 = {
    name: {
        first: "Alex",
        last: "Telles"
    },
    address: "Toronto"
}

const person2 = {...person1};
person2.name.first = "John";

console.log(person1);
Enter fullscreen mode Exit fullscreen mode

This is our expected output:

{
    name: {
        first: "Alex",
        last: "Telles"
    },
    address: "Toronto"
}
Enter fullscreen mode Exit fullscreen mode

But, what we get:

{
    name: {
        first: "John",
        last: "Telles"
    },
    address: "Toronto"
}
Enter fullscreen mode Exit fullscreen mode

The person1 also got changed even if we used spread operation to create a new object.

This is because, the spread operator only affects the first level properties and it won't clone the deep level key values. So, the first in the name property still has the memory reference to its parent.

Here is the solution to deep clone JS objects:

JSON stringify

const person2 = JSON.parse(JSON.stringify(person1));
Enter fullscreen mode Exit fullscreen mode

Converting the object to string and then into JSON resolves the problem.

But still, we have a problem.

function test() { console.log("This is a Test") }

const person1 = {
  name: {
    first: "Alex",
    last: "Telles"
  },
  f: test,
  address: "Toronto"
}
person1.f()

const person2 = JSON.parse(JSON.stringify(person1));

person2.f()
Enter fullscreen mode Exit fullscreen mode

This code will return an error saying TypeError: person2.f is not a function. This is because, we had a memory reference to the function in the parent object and when we converted it into string for cloning, that reference got lost.

thanks to @efpage for the feedback.

So, there are some ways to overcome this:

Using loadash

const _ = require('lodash');

function test() { console.log("This is a Test") }

const person1 = {
  name: {
    first: "Alex",
    last: "Telles"
  },
  f: test,
  address: "XYZ"
}

const person2 = _.cloneDeep(person1);
person2.f();
Enter fullscreen mode Exit fullscreen mode

lodash library has a cloneDeep function which will help to deep clone object with all memory reference.

Structured clone function

const person2 = structuredClone(person1);
Enter fullscreen mode Exit fullscreen mode

The structuredClone function will be available in the new version of JavaScript and it will deep copy the parent object.

Hope this articles helped you. Drop your feedbacks in comments.

Top comments (3)

Collapse
 
efpage profile image
Eckehard

'JSON.stringify' does not work if you use any memory references in your object:

function test() { console.log("This is a Test") }

const person1 = {
  name: {
    first: "Alex",
    last: "Telles"
  },
  f: test,
  address: "XYZ"
}
person1.f()

const person2 = JSON.parse(JSON.stringify(person1));

person2.f() //Uncaught TypeError TypeError: person2.f is not a function
Enter fullscreen mode Exit fullscreen mode

Intrestingly, f is completely skipped in the output:

JSON.stringify(person1) -> {"name":{"first":"Alex","last":"Telles"},"address":"XYZ"}
Enter fullscreen mode Exit fullscreen mode
Collapse
 
pulimoodan profile image
Akbar Ali

Yeah, that's a concern.

So, structuredClone is the only way.

Is there any other workaround?

Collapse
 
pulimoodan profile image
Akbar Ali

I am gonna edit my article with these later