3

Below is my code to change an object inside an array into a string. Can't figure out why it effects the original array. slice is supposed to clone array, if I am right?

var cloned = $scope.selected.items.slice(0);
cloned.forEach(function (cluster) {
  cluster.status = cluster.status.name;
})
ObjToPost.MO = cloned;
console.log("consoling the cluster list", ObjToPost.MO);
console.log("consoling the original cluster list", $scope.selected.items);

After consoling both the arrays are same

thefourtheye
  • 233,700
  • 52
  • 457
  • 497
Saurabh Tiwari
  • 4,632
  • 9
  • 42
  • 82
  • 1
    I don't see you cloning anything! The cloned is a direct reference for the original list. – Fals Oct 02 '15 at 12:43

2 Answers2

7

Quoting MDN on Array.prototype.slice,

The slice() method returns a shallow copy of a portion of an array into a new array object.

The important words here are "shallow copy". It creates a new Array and makes the elements of the array point to the same object.

In your case, even after slicing, each of the array elements in both the original and cloned arrays refer the same cluster objects in memory.

Original                        Cloned
+-----+                        +-----+
|  0  |--> Cluster Object 1 <--|  0  |
+-----+                        +-----+
|  1  |--> Cluster Object 2 <--|  1  |
+-----+                        +-----+
|  2  |--> Cluster Object 3 <--|  2  |
+-----+                        +-----+

Since all the corresponding elements are referring to the same objects, changing it through one array will be reflected in the other as well.

Note: If you are looking for a way to do deep copy, then you might want to check this question.

Community
  • 1
  • 1
thefourtheye
  • 233,700
  • 52
  • 457
  • 497
  • Is there a way around to copy the array – Tushar Oct 02 '15 at 12:49
  • What I want is that original array should remain unaffected, and I should get a temporary copy of same array, which by the way I need to POST after modifying it – Saurabh Tiwari Oct 02 '15 at 13:19
  • I tried using $.extend, but it seems it can clone only objects and not array, whereas arrays are also objects – Saurabh Tiwari Oct 02 '15 at 13:21
  • @SaurabhTiwari The best way is to write a function which clones the clusterObjects and then invoke it like this `var clonedArray = original.map(cloneCluster)` – thefourtheye Oct 02 '15 at 13:28
0

As @thefourtheye explained, you are creating a shallow copy of the array. To deep copy the array items, and modify the status, you can use Array.prototype.map with angular.merge():

ObjToPost.MO = $scope.selected.items.map(function(cluster) {
    return angular.merge({}, cluster, { status: cluster.status.name }); // create a deep copy of each item, and override status with status.name
});
Ori Drori
  • 183,571
  • 29
  • 224
  • 209