4

I have a file where I'm exporting an object like this:

export const LINECHART2_DATA = {
    series: [{
        data: [],
        name: 'HR',
    },
    { 
        etc...
    }]
}

I'm importing it like this:

import { LINECHART2_DATA } from '../chart-options/options';

I have the following method:

prepareLineChartDataContainer(bed: BedDetails) {
//Clear data to prepare for new bed
if (bed.seriesContainer == null) {
  bed.seriesContainer = LINECHART2_DATA.series.slice();
} else {
  bed.seriesContainer.forEach(series => {
    series.data.length = 0;
  });
}
//Add data to seriesContainer
this.vitalSigns.forEach(vs => {
  bed.timeWindows.forEach(tw => {
    bed.seriesContainer.find(series => series.name == vs).data.push(tw['avg' + vs]);
  });
});
}

As you can see above, I'm slicing the series array from LINECHART2_DATA, then pushing some data to it. When a new bed is passed into the method with a null seriesContainer, it will be sliced once again, but this time it will contain the data that was added by the previous bed. Since I am using slice(), I was expecting to just get the value of LINECHART2_DATA, not the reference. What am I doing wrong?

Jesper
  • 2,644
  • 4
  • 30
  • 65
  • 3
    slice() always returns a new Array, rtfm – dandavis Apr 06 '18 at 20:10
  • 1
    @dandavis No need to be rude, why do you think I wrote that I expected to get a new array? Clearly that is not what I am getting, though, since mutating the "new array" also mutates the original one that i sliced. – Jesper Apr 06 '18 at 20:12
  • 1
    @Jesper Is the array mutating, or is the data in the array mutating? – Clint Apr 06 '18 at 20:13
  • 1
    sorry, i was going for funny... i don't see you mutating the old or new array, just the elements, which are passed "byref". think of the array as a bus and the riders as elements; they can board a new bus without becoming new people. – dandavis Apr 06 '18 at 20:13
  • 3
    The array you get back from `.slice` is a *shallow copy*, which means that while the array IS new, the entries in that new array are references pointing to the same objects as the original. So when you mutate them, it will change the original objects as well. – CRice Apr 06 '18 at 20:14
  • try deep cloning it – Satish Kumar Apr 06 '18 at 20:16
  • 1
    @CRice: both arrays have the exact same values, there's no "as well" or "original objects", they are all refs to the same objects. clear as mud object passing in JS is... – dandavis Apr 06 '18 at 20:16
  • @dandavis How is it "clear as mud"? Seems pretty standard in languages that pass by value. – Clint Apr 06 '18 at 20:23
  • Possible duplicate of [How do you clone an Array of Objects in Javascript?](https://stackoverflow.com/questions/597588/how-do-you-clone-an-array-of-objects-in-javascript) – Clint Apr 06 '18 at 20:26
  • 1
    @Clint: as evidenced by the very conversation this question sparked. i don't think it's surface-apparent that we're always actually passing values around, or that some of those values happen to be references to objects. it makes it seems like there's a diff between passing numbers and objects, when there's (under the hood) not, but above ground, it seems to be different. – dandavis Apr 06 '18 at 20:28

2 Answers2

10

From the documentation of Array.slice:

slice does not alter the original array. It returns a shallow copy of elements from the original array. Elements of the original array are copied into the returned array as follows:

For object references (and not the actual object), slice copies object references into the new array. Both the original and new array refer to the same object. If a referenced object changes, the changes are visible to both the new and original arrays.

For strings, numbers and booleans (not String, Number and Boolean objects), slice copies the values into the new array. Changes to the string, number or boolean in one array do not affect the other array. If a new element is added to either array, the other array is not affected.

So the behaviour you're seeing is a consequence of the shallow copy behavior of slice. If you need a deep copy so that you can freely mutate the objects without affecting the originals, you'll need to do that manually. The answers to this question show a few ways of doing so.

Community
  • 1
  • 1
CRice
  • 29,968
  • 4
  • 57
  • 70
0

To prevent mutating elements of copied array you should create a copy of items as well:

 bed.seriesContainer = LINECHART2_DATA.series.map((item=>Object.assign({}, item, {data: item.data.slice()}))
Oleksandr Poshtaruk
  • 2,062
  • 15
  • 18