Mr.Smithyyy
Mr.Smithyyy

Reputation: 1329

Why does modifying this property affect another this property

I have a class which looks similar to what is shown below and it keeps track of imaginary muffins. When the class is instantiated it begins with a blank slate of no muffins.

Of course it would be nothing without the ability to add muffins so that's a feature but there's nothing special about it. It just takes an array of objects and pushes them to this.muffins.

Also these muffins need to be lent out but not eaten because they are too good looking and are only to be used for decoration. However, when these muffins are lended out, they should be removed from this.muffins and be kept in their own object under this.lent so that they cannot be lended out until returned.

The problem is that as I try to remove the muffins from this.muffins after I add them to this.lent, it also removes them from this.lent. I do not know why this happens because I do not understand why they are tied together. I'm confused as to why modifying the muffin array after adding the muffin to this.lent also affects the muffin in this.lent.

class Muffins {
    constructor() {
        this.muffins = [];
    }

    add(muffins) {
      // Add your muffins here.
    }

    loan(numOfPeople, numOfMuffins) {
        const totalMuffinsToLend = numOfPeople * numOfMuffins;

        for (let i = 0, person = 0; i < totalMuffinsToLend; ++i, ++person) {
            if (person >= numOfPeople) person = 0;

            if (!this.lent[person + 1]) this.lent[person + 1] = [];

            this.lent[person + 1].push(this.muffins[i]);

            this.muffins.filter(muffin => {
                if (muffin.id == this.muffins[i].id) this.muffins.splice(this.muffins.indexOf(muffin), 1);
            });
        }
    }
}

For reference, this.muffins looks similar to:

[
    { id: 1, type: blueberry },
    { id: 2, type: strawberry },
    // etc.
]

and this.lent looks like:

{
    '1': { id: 1, type: blueberry },
    '2': { id: 2, type: strawberry },
    // etc.
}

Upvotes: 0

Views: 63

Answers (2)

Nimeshka Srimal
Nimeshka Srimal

Reputation: 8930

This refers to my comment on your question. Objects are passed by reference and that's the reason why you see that behavior in your example.

To overcome this, you have to create a copy of your original object (Not passing its reference).

Instead of using JSON.parse(JSON.stringify()), you could use Object.assign() as it's a straightforward approach as well as it's better in terms of performance.

You can change your code to something like this:

this.lent[person + 1].push(Object.assign({}, this.muffins[i]));

One thing you need to notice is that Object.assign() creates a shallow copy (which is enough for your example). But JSON.parse(JSON.stringify()) serializes the whole thing and creates everything from scratch. That's one reason why Object.assign() is faster.

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign

Hope it helps!!

Upvotes: 0

jshamble
jshamble

Reputation: 491

You can clone the object then copy the instance over:

var muffin_clone = JSON.parse(JSON.stringify(this.muffins[i]));
this.lent[person + 1].push(muffin_clone);

for more efficient cloning methods please read this

Upvotes: 2

Related Questions