7

I am having trouble maintaining the original value of a variable after making new changes to the original variable.

Code:

(...)
data = Illumination.calculate_N(data)
data = Illumination.calculate_pi(data)
data = Illumination.calculate_kwh(data)
data = Illumination.calculate_ca(data)           

let data_base = data

let ca_base = data.ca
let kwh_base = data.kwh
let pi_base = data.pi

(...)

data = Illumination.calculate_N(data)
data = Illumination.calculate_pi(data)
data = Illumination.calculate_kwh(data)
data = Illumination.calculate_ca(data)            

let data_proposto = data

let ca_proposto = data.ca
let kwh_proposto = data.kwh
let pi_proposto = data.pi

-----------------------------------
EXAMPLE:
static calculate_ai(data){
  data.ai = data.areaTotal*data.au
  return data
} 

It was expected that the original variable (date) would have its values ​​changed, and this happens correctly, however, the variables data_base and data_proposto are not keeping their values

Both variables at the end of the calculation have the same values ​​as the variable date

The variables ca_proposto, ca_base, and the like store their values ​​correctly

Any idea?

The only interactions of the variables data_base and data_proposto were their creations with the data variable and their return of the function

OBS: If I use console.log () to view the value of the data_base variable before redoing the new calculations (Illumination.calculate_N (data)), the value of the variable appears correctly as it should, it is changed shortly after these calculations.

  • `data_base` and `data_proposto` are pointing to the same object in memory. As long as `data` changes, both will reflect the change since they point to the same object. – briosheje May 09 '19 at 04:55
  • if your using objects..it will get mutated.You need to use Object.Assign to avoid mutation for one level nesting ,for example var a = {b:"text"};var clonedA = Object.Assign({},a).If its multiple level of nesting ,then you can use JSON.parse(JSON.stringify(a)),but it has some limitations as well as its time consuming – Rajesh Kumaran May 09 '19 at 04:55
  • I figured that maybe would be the problem, but did not javascript create a COPY of the variable? In this case it looks like a pointer – João Pedro Silva Dezembro May 09 '19 at 04:57
  • Rajesh Kumaran Yes, they are objects. I will try this solutions, and they have only 1 level of nesting – João Pedro Silva Dezembro May 09 '19 at 04:58
  • Rajesh Kumaran In case, I got an error when using the Object.Assign, it is probably the version of NodeJS (or it does not support itself), but JSON.parse worked! Although it is more expensive the object I am working with is relatively simple. Thank you! – João Pedro Silva Dezembro May 09 '19 at 05:03
  • Possible duplicate of [Is JavaScript a pass-by-reference or pass-by-value language?](https://stackoverflow.com/questions/518000/is-javascript-a-pass-by-reference-or-pass-by-value-language) – stealththeninja May 09 '19 at 05:10

4 Answers4

7

Because in both cases you are assigning not the object itself in the current state, but a reference to that object. What you need to do is to clone the object so the state is frozen at that point.

Simple Clone (Shallow Copy)

let data_base = Object.assign({}, data); //you get a clone of data 

let data_proposto = Object.assign({}, data); 

The limitation here is that it only does a shallow copy. See Deep Copy below for further explanation.

JSON Clone

This is a quick-and-dirty way to clone as it converts a JSON object to a string, and then back. i.e. you are no longer getting a reference, but a new object.

let data_base = JSON.parse(JSON.stringify(data));

let data_postero = JSON.parse(JSON.stringify(data));

But this won't work if your object is not JSON-safe.

Deep Copy

The least elegant method is probably safest. It deep copies the properties over into a new object. The key difference with Object.assign() is that it copies the values of nested properties, whereas Object.assign() copies the reference to nested objects.

So with Object.assign() any subsequent changes in your nested objects will affect all versions of your "clones". This won't happen if your clones only have property values of those nested objects at the time of cloning – these values are not affected by any changes to the nested objects.

const deepCopy = function(src) {
let target = {};
// using for/in on object also returns prototype properties
for (let prop in src) {
    // .hasOwnProperty() filters out these prototype properties.
    if (src.hasOwnProperty(prop)) {
        target[prop] = src[prop]; //iteratively copies over values, not references
    }
}
return target;
}

let data_base = deepCopy(data);

let data_postero = deepCopy(data);
chatnoir
  • 2,185
  • 1
  • 15
  • 17
  • Yes! this is the problem, however the Object.assign is not natively supported on the NodeJS. Besides the response from Rajesh Kumaran (JSON.parse ()), would you indicate any other solution more suitable and compatible with nodeJS? – João Pedro Silva Dezembro May 09 '19 at 05:08
  • Sure, see last Deep Copy solution :D. Btw Object.assign() worked for me in Node.js@10.15.1 – chatnoir May 09 '19 at 05:20
2

@chatnoir Defined the problem very well, But I do not agree with his JSON serialization solution due to the below probleam:

You will lose any Javascript property that has no equivalent type in JSON, like Function or Infinity. Any property that’s assigned to undefined will be ignored by JSON.stringify, causing them to be missed on the cloned object.

My suggestion to perform deep copy is to rely on a library that’s well tested, very popular and carefully maintained: Lodash.

Lodash offers the very convenient clone and deepclone functions to perform shallow and deep cloning.

Lodash has this nice feature: you can import single functions separately in your project to reduce a lot the size of the dependency.

Please find the running sample code here: https://glitch.com/edit/#!/flavio-lodash-clone-shallow-deep?path=server.js:1:0

Shivang Agarwal
  • 1,825
  • 1
  • 14
  • 19
1

You are using the same variable data inside and outside functions.

ie; data is in the global scope.

static calculate_ai(data){
  data.ai = data.areaTotal*data.au
  return data
}

even though you are expecting the scope of the variable data inside the method calculate_ai to be limited to that method, it is not the case. data is in global scope and therefore, the value changes inside the method for the variable affects outside as well.

An effective solution is to use a different variable inside the method.

Jacob Nelson
  • 2,370
  • 23
  • 35
0

A variable is like an octopus tentacle, and not as a box (as it’s commonly described). In this analogy, the variable's name can be thought of as the name of a tentacle.

A variable (tentacle) holds on to a value in what’s called a binding. A binding is an association of a variable to a value: x = 1.

In JavaScript, if a variable b holds on to variable a, changing the value to which variable a holds onto, will change the value to which variable b holds onto, as b and a are referencing to the same value:

let a = {key: 1}
let b = a
console.log(`a: ${a.key}`) // -> 1
console.log(`b: ${b.key}`) // -> 1

a.key = 2
console.log(`a: ${a.key}`) // -> 2
console.log(`b: ${b.key}`) // -> 2

a = {key: 3} // This will point variable 'a' to a new object, while variable 'b' still points to the original object. 
console.log(`a: ${a.key}`) // -> 3
console.log(`b: ${b.key}`) // -> 2
Damian Demasi
  • 71
  • 1
  • 6