Object memory reference in JS
Tags: javascript, webdev, beginners, programming
Published: 2024-03-12 20:05:52

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

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

console.log(person1);
```

What would be the output of the above code?

Does that look like this:

```json
{
    name: "Alex",
    address: "Toronto"
}
```
You're wrong. It would look like this:

```json
{
    name: "John",
    address: "Toronto"
}
```
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**
```js
const person1 = {
    name: "Alex",
    address: "Toronto"
}

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

console.log(person1);
```
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:
```js
const person1 = {
    name: {
        first: "Alex",
        last: "Telles"
    },
    address: "Toronto"
}

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

console.log(person1);
```

This is our expected output:
```json
{
    name: {
        first: "Alex",
        last: "Telles"
    },
    address: "Toronto"
}
```

But, what we get:
```json
{
    name: {
        first: "John",
        last: "Telles"
    },
    address: "Toronto"
}
```
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**
```js
const person2 = JSON.parse(JSON.stringify(person1));
```
Converting the object to string and then into JSON resolves the problem.

But still, we have a problem. 

```js
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()
```
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**
```js
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();
```
lodash library has a cloneDeep function which will help to deep clone object with all memory reference.

**Structured clone function**
```js
const person2 = structuredClone(person1);
```
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.