Why does modifying this property affect another this property

时间:2018-07-24 10:23:23

标签: javascript

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.
}

2 个答案:

答案 0 :(得分:2)

您可以克隆对象,然后将实例复制到以下位置:

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

有关更有效的克隆方法,请阅读this

答案 1 :(得分:0)

这是我对您的问题的评论。对象是通过引用传递的,这就是为什么您在示例中看到该行为的原因。

要解决此问题,您必须创建原始对象的副本(不传递其引用)。

您可以使用JSON.parse(JSON.stringify())而不是使用Object.assign(),因为它是一种直接的方法,并且在性能方面也更好。

您可以将代码更改为以下内容:

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

您需要注意的一件事是Object.assign()创建了一个浅表副本(对于您的示例来说足够了)。但是JSON.parse(JSON.stringify())将整个序列序列化并从头开始创建所有东西。这就是Object.assign()更快的原因之一。

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

希望有帮助!