1

The code below declares an input_data as a const variable that is never modified in the lifetime of the execution. I expect every console.log to output the same thing 3 times but that is not the case.

This code is modified to be minimal and easily understandable and reflects the functions and promises am using in the real code. Could you tell me how and why this is happening and also show a working code with the same structure that doesn't modify that const variable

const platform = "test";
const input_data = {
  "test": true
};

function verify(data) {
  let cmd = input_data;
  cmd.valid = true;
  return cmd;
}
console.log("#req", input_data);
let command = verify(input_data);
console.log("#req", input_data);

new Promise((resolve, reject) => {
  command.executed = true;
  resolve("successs")
}).then(result => {
  console.log("#req", input_data);
});

Below is the output I get

#req { test: true }
#req { test: true, valid: true }
#req { test: true, valid: true, executed: true }

Instead it should be like this

#req { test: true }
#req { test: true }
#req { test: true }
Satpal
  • 132,252
  • 13
  • 159
  • 168
Disney Program
  • 310
  • 2
  • 9
  • 1
    javascript does assignment by reference. And declaring an object as const does not prevent you from changing the values at its keys. – The Fool Sep 23 '20 at 08:51
  • good point @TheFool, but am not changing the values on `input_data` – Disney Program Sep 23 '20 at 08:52
  • 2
    yes you do. `let cmd = input_data` now command is your input object as it is a refence to the original. When you then do `cmd.valid = true` you added another key / value pair to the original object but you didnt violate the const. – The Fool Sep 23 '20 at 08:53
  • 1
    https://stackoverflow.com/questions/6732589/javascript-equivalent-of-assign-by-reference – The Fool Sep 23 '20 at 08:55
  • `cmd` is a different variable here which is being modified, the real victim is `input_data` who is never modified – Disney Program Sep 23 '20 at 08:56
  • 1
    because cmd is referencing input_data. I told you now three times. Please go learn about assignment by refrence. – The Fool Sep 23 '20 at 08:56
  • 1
    if you want to prevent it, by the way, create a fresh brand new object. With es6 you could do `let cmd = {...input_data, valid: true}` – The Fool Sep 23 '20 at 08:58
  • easy @TheFool, thanks for your help, I hadnt come across this before. – Disney Program Sep 23 '20 at 09:03
  • @DisneyProgram, Use `let cmd = Object.assign({}, input_data);` this will shallow copy properties – Satpal Sep 23 '20 at 09:18
  • yep, I just found it on https://stackoverflow.com/questions/7574054/javascript-how-to-pass-object-by-value but i would never find that question if it were not for you guys because of the phrases – Disney Program Sep 23 '20 at 09:23

1 Answers1

1

You are doing assignment by reference.

When you do let cmd = input_data you reference the 'input_data' object. Meaning any change to cmd will reflect in input_data.

You can prevent this by creating a new object.

es5

let cmd = Object.assign({}, input_data, {valid: true})

es6

let cmd = {...input_data, valid: true}

So the final code would be

const platform = "test";
const input_data = {"test": true};

function verify(data){
    let command = Object.assign({}, data);
    command.valid = true;
    return command;
}
console.log("#req", input_data);
let command = verify(input_data);
console.log("#req", input_data);

new Promise( (resolve, reject) => {
    command.executed = true;
    resolve("successs")
}).then( result => {console.log("#req", input_data);});
The Fool
  • 16,715
  • 5
  • 52
  • 86