2

I am encountering a weird problem with what I believe to be the way Javascript references variables. The project I am working in is Typescript, but this functionality is from vanilla Javascript.

I have an object all_obj set further up in the code.

The following code:

all = [];
data = [];

console.log(all_obj);

Outputs:

{
  "1593561600000": {
    "date": 1593561600000,
    "volume": 24463,
    "value": 165049285,
    "rank": 0
  },
  "1596240000000": {
    "date": 1596240000000,
    "volume": 24366,
    "value": 158841976,
    "rank": 0
  },
  "1604188800000": {
    "date": 1604188800000,
    "volume": 30034,
    "value": 196655815,
    "rank": 0
  },
  This goes on 9 more times with similar objects
}

This, works as expected.

However the following code somehow logs something completely different:

let all = [];
let data = [];

console.log(all_obj);

for (let key of Object.keys(all_obj)) {
  all.push(all_obj[key]);
}

this.data.push(
  {
    brand: 'all_aggregated',
    datapoints: [...all],
  },
  {
    brand: 'all_mean',
    datapoints: [...all].map((dp: brand_datapoint) => {
      dp.value = +(dp.value / dp.volume).toFixed(2);

      return dp;
    }),
  }
);

It logs this:

{
  "1593561600000": {
    "date": 1593561600000,
    "volume": 24463,
    "value": 6746.89,
    "rank": 0
  },
  "1596240000000": {
    "date": 1596240000000,
    "volume": 24366,
    "value": 6519,
    "rank": 0
  },
  "1604188800000": {
    "date": 1604188800000,
    "volume": 30034,
    "value": 6547.77,
    "rank": 0
  },
  9 more like this
}

As you can see, in the second example. The "value"'s within the all_obj's children is now in the thousands, instead of the hundreds of millions. Also, it is formatted to 2 decimal places. This is suspiciously the formatting I am doing in this line towards the end of the second code example:

dp.value = +(dp.value / dp.volume).toFixed(2);

How on earth is changing the values propagating back up the code???

Especially through [...all]

This is running in an Angular Project. I have trimmed off the bloat, if you need more info of course ask for it, but I didn't want to paste 300 lines of code in here :)

I have been fighting with this for about 6 hours now, and have completely rewritten the same code in about 15 different ways. So I am completely baffled what is causing this.

Solution! The issue isn't that the data is propagating back up to all_obj, it's that values were being set in the pink arrow, and were being picked up in the red arrow because they were just referencing to it. I thought [...all] would fix it but that just builds a new array with the same references.

enter image description here

1 Answer 1

1

The problem is that you are editing the value on the same object that you started with.

When you do all.push(all_obj[key]);, you are filling all with a bunch of references to the inner objects in all_obj. Since these are simply references, interacting with them changes the same objects as the the ones in all_obj. So when you set the value dp.value =, it is "propagating back up the code" because it is the same object that is inside all_obj.

Since you want to make these changes on a new object for just formatting reasons, you should make a copy of the object and only edit the values there. Since the datapoints seem to be simple, with only simple numbers as properties, you can easily make a copy with

dp = {...dp};

You should do this before you change the value.

You may be thinking that this shouldn't be needed, because of the [...all]. However, that will only make a copy of the all list itself, not of all the content. So basically it is a "new list" that contains all the same references to all the same objects.

You may be interested in Is JavaScript a pass-by-reference or pass-by-value language?

EDIT:

Taking another look, it would probably be better/cleaner to make the copy right as you are building the all array. So instead of doing

all.push(all_obj[key]);

You can do

all.push({...all_obj[key]});

Then you don't need to worry about changing the original data as you manipulate the points for formatting or display.

Sign up to request clarification or add additional context in comments.

1 Comment

You are a star. I was doing all_obj = {...all_obj}, then I thought maybe that doesn't redeclare it but just put references to it's children in a new object. So I was doing JSON.parse(JSON.stringify()) etc. And I was wondering why it wasn't working. But the whole time it was the issue of remaking dp. Thank you!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.