更改对象会导致所有对象发生更改

时间:2015-07-08 13:55:51

标签: javascript

有这种类型的对象。 在FabricJS画布中创建elemens并设置属性:

canvas.forEachObject(function (e) {
        e.hasControls = e.hasBorders = false; //remove borders/controls
        e.isStatic = true;
        e.corners = [false, false, false, false, false];
    });


fitElement.destination.corners[1] = true;
fitElement.origin.corners[3] = true;

console.log(fitElement.destination.corners);
console.log(fitElement.origin.corners);

结果是

[false, true, false, true, false]
[false, true, false, true, false]

为什么在对象中更改一个数组会导致另一个数组的变化? 我做错了什么? 感谢

2 个答案:

答案 0 :(得分:1)

只有一个解释:ConditionalAttributefitElement.destination.corners是完全相同的数组。

在代码的某处,您将一个数组或对象分配给另一个,因此您在内存中引用相同的数据,例如:

fitElement.origin.corners

或者:

var vector5 = new Vector5(); // of my invention, just to explain the concept

fitElement.origin.corners = vector5;
fitElement.destination.corners = vector5;

或者在嵌套中加强:

fitElement.origin.corners = vector5;
fitElement.destination.corners = fitElement.origin.corners;

答案 1 :(得分:1)

绝大多数对象的JavaScript变量都是引用,这导致了这样的问题。在代码中的某个地方,您几乎肯定会相当于destination.corners = foo; ... origin.corners = foo;并最终为两者使用相同的数组。

您可以通过在分配后询问fitElement.destination.corners === fitElement.origin.corners是否足够轻松地进行测试。 ===strict equality)运算符检查两个变量是否引用同一个对象。在这种情况下,我会打赌他们这样做,这就是问题的根源。

根据我的经验,意外执行此操作的最常见方式是传递父对象或从碰巧指向同一数组的一个或多个对象获取属性。例如,做:

var foo = {bar: [1, 2, 3]};
var baz = _.extend({}, foo); // create a "copy"

foo.bar[1] = 9;
console.log(baz.bar);

在克隆父对象(foo - > baz)并foo !== baz时,子(bar且对foo.bar的任何更改也会影响baz.bar

提供复制/克隆/扩展功能的库也可以提供深度克隆,它将沿着对象走下来并克隆任何子节点(例如,lodash提供clonecloneDeep。 / p>

在您的情况下,由于您单独使用数组,我建议在将它们分配到角落之前制作每个数据的副本。您可以使用slice复制数组:

var defaultCorners = [false,false,false,false,false];
var destCorners = defaultCorners.slice();
var originCorners = defaultCorners.slice();

fitElement.destination.corners = destCorners;
fitElement.origin.corners = originCorners; 

destCorners[1] = true;
originCorners[3] = true;

console.log(fitElement.destination.corners);
console.log(fitElement.origin.corners);

这样可以避免这个问题,但请记住:slice生成另一个浅拷贝,因此数组中的任何对象都会遇到同样的问题。