Arthur
Arthur

Reputation: 179

Changing object causes changes in all objects

have such type of object. Creating elemens in FabricJS canvas and setting attributes:

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);

And the result is

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

Why changing one array in object causes the chages of another? What I am doing wrong? Thanks

Upvotes: 0

Views: 87

Answers (2)

ssube
ssube

Reputation: 48247

JavaScript variables for the vast majority of objects are references, which leads to issues like this. Somewhere in your code, you almost certainly do the equivalent of destination.corners = foo; ... origin.corners = foo; and end up using the same array for both.

You can test this easily enough by asking if fitElement.destination.corners === fitElement.origin.corners after assigning. The === (strict equality) operator check if both variables reference the same object. In this case, I'll bet they do and that's the source of your problem.

The most common way of accidentally doing that -- in my experience -- is passing a parent object or taking a property from one or more objects that happen to point to the same array. For example, doing:

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

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

While the parent object (foo -> baz) is cloned and foo !== baz, the child (bar) is not and any changes to foo.bar will also affect baz.bar.

Libraries that offer a copy/clone/extend function may also provide a deep clone that will walk down the object and clone any children as well (for example, lodash provides clone and cloneDeep.

In your case, since you're using the arrays individually, I would suggest making a copy of each just before assigning them to the corners. You can copy an array with 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);

This will avoid the problem, but remember: slice makes another shallow copy, so any objects within the array will have this same issue.

Upvotes: 1

pid
pid

Reputation: 11597

There's only one explanation: fitElement.destination.corners and fitElement.origin.corners are the very same array.

Somewhere up in the your code you assign one array or object to the other, so you are referencing the same data in memory, for example:

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

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

Or:

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

Or a step up in the nesting:

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

Upvotes: 1

Related Questions