Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

For a deep copy of a JavaScript multidimensional array, going one level deep seems sufficient. Is this reliably true?

Note: I'm only a novice coder, so there might be a glaring error or misconception at the heart of this question.

Essentially, I need to deep copy multidimensional arrays 'by value' in JavaScript to an unknown depth. I thought this would require some complex recursion, but it seems that in JavaScript you only need to copy one level deep in order to copy the whole array by value.

As an example, here is my test code, using a deliberately convoluted array.

function test() {
  var arr = [ ['ok1'],[],[ [],[],[ [], [ [ ['ok2'], [] ] ] ] ] ];
  var cloned = cloneArray(arr);
  arr = '';   // Delete the original
  alert ( cloned );
}


function cloneArray(arr) {  
  // Deep copy arrays. Going one level deep seems to be enough.
  var clone = [];
  for (i=0; i<arr.length; i++) {
    clone.push( arr[i].slice(0) )
  }
  return clone;
}

In my running of this test (latest stable Chrome and Firefox on Ubuntu), even the deepest parts of the array seem to be successfully copied by value in the clone, even after the original is deleted, despite the fact that the slice() "copying" only went one layer deep. Is this the standard behaviour in JavaScript? Can I depend on this to work for older browsers?

like image 843
user2625911 Avatar asked Aug 03 '14 01:08

user2625911


1 Answers

Your test is flawed for whether a true copy is being made which makes your conclusion incorrect that you are getting a full copy of all the data in the nested arrays. You are only doing a two level copy, not an N level copy.

Javascript is a garbage collected language so you don't actually delete variables or objects and, even if you tried that doesn't affect the same variable if it's being referenced somewhere else in your code. To see if you truly have a completely independent copy, try nesting an object two levels deep and then change a property on the object in the original array. You will find that the same object changes in the cloned array because you aren't doing a deep clone. Both arrays have a reference to the exact same object.

Here's an example.

function cloneArray(arr) {  
  // Deep copy arrays. Going one level deep seems to be enough.
  var clone = [];
  for (i=0; i<arr.length; i++) {
    clone.push( arr[i].slice(0) )
  }
  return clone;
}

var x = [[{foo: 1}]];

var y = cloneArray(x);
x[0][0].foo = 2;

// now see what the value is in `y`
// if it's 2, then it's been changed and is not a true copy
// both arrays have a reference to the same object
console.log(y[0][0].foo);    // logs 2

The same result would happen if the third level was another array too. You will have to recursively traverse every element that is an object type and then clone that object itself to get a complete clone of everything in the nested arrays.

If you want code that will do a deep copy (to an arbitrary level) and work for all data types, see here.

FYI, your cloneArray() function assumes that all first level members of your array are arrays themselves and thus doesn't work if it contains any other type of value.

like image 158
jfriend00 Avatar answered Oct 12 '22 23:10

jfriend00