0

I have the following code.When I access w[1][0], I want only the object at that one location to be changed. However, all the objects change instead. I'm assuming this is because at some level, they are all pointing to the same object. How would I fix this?

 var createArray = function(dim,init){//takes an array of dimensions and the initial value of each element
    if(dim.length > 0){
        var x = new Array();
        for(var i = 0; i < dim[0]; i++)
            x[i] = createArray(dim.slice(1),init)
        return x;
    }
    return init;
}

var w = createArray([2,2],{top: false,left: false});
console.log(w);
w[1][0].left = true;
console.log(w);
jwesly
  • 19
  • 4
  • Cloning objects is a not that trivial topic. You should read this: http://stackoverflow.com/questions/122102/what-is-the-most-efficient-way-to-clone-an-object – idmean Jul 31 '15 at 17:30
  • Sure it is! ` – Plato Jul 31 '15 at 20:47

2 Answers2

1

In JavaScript, objects are passed by a reference, not by value. That means that if you pass the same object to a few variables, they all point to the same place in memory. This is why your init object is being changed everywhere.

To prevent this, you need to clone the object before assigning it to your variables. One of the simplest built-in methods is to use JSON, like this:

var copy = JSON.parse(JSON.stringify(original));

So in your case that would be it:

x[i] = createArray(dim.slice(1), JSON.parse(JSON.stringify(init)));
Robo Robok
  • 21,132
  • 17
  • 68
  • 126
  • Er...good explanation, and I hadn't thought of cycling through JSON, BUT, I think this will still only create one instance of the object, and that will be maintained through the recursive function – Katana314 Jul 31 '15 at 17:35
  • Thanks, was not aware that objects were passed by reference until getting this problem. I chose yours over Katana's for the explanation and more elegant (i think) one line solution – jwesly Jul 31 '15 at 17:56
  • Note that `JSON.parse(JSON.stringify({ ... }))` will destroy any properties with a function value – Plato Jul 31 '15 at 20:49
0
w[1][0].left = true;

This line is changing the only instance of the object. See, this line:

var w = createArray([2,2],{top: false,left: false});

is the only line in your code that creates a new object (of the type you're interested in) via the {} literal there. All other set operations (newVar = init) only copy a reference to that same object.

That sounds annoying, but it has a lot of good uses in code. To fix it, you'll want to create a copy each time, to replace the final line of createArray

var myCopy = {};
for (var key in origObject) {
  if (origObject.hasOwnProperty(key)) {
    myCopy[key] = origObject[key];
  }
}
return myCopy;

Be warned - this is a "shallow copy", so it will only copy the top-level properties, and any objects a level deep will still be references. Many JavaScript libraries have functions to create deep copies for you.

Katana314
  • 8,429
  • 2
  • 28
  • 36