-2

I'm working through my course, and keep hitting the same speedbumb. My mental model for why the following behavior is lacking. I'm after as simple an explanation as possible to fill the gap :)

In the following snippet the reassignment doesn't occur for the qux variable when it's name is passed into the function.

let foo = {a: 'hello',b: 'world'};
let qux = 'hello';

function bar(argument1, argument2) {
  argument1.a = 'hi';
  argument2 = 'hi';
}

bar(foo, qux);

console.log(foo.a); // Logs 'hi'
console.log(qux); // Logs 'hello'

But in the below example, when the variable name is explicitly referenced in the function, and the value is passed as an argument, then the reassignment occurs.

let foo = {a: 'hello',b: 'world'};
let qux = 'hello';

function bar(argument1, argument2) {
  argument1.a = 'hi';
  qux = argument2;
}

bar(foo, 'hi');

console.log(foo.a); // Logs 'hi'
console.log(qux); // Logs 'hi'

I understand object values are mutable, and primitive values are not. However, I don't understand why JS is not reassigning the variable in both instances?

I've reviewed this question, the answers to which go into some depth, but I can't seem to see a specific answer for why the reassignment specifically isn't happening.

Brucie
  • 51
  • 8
  • `argument2 = 'hi'` assigns "hi" to `argument2`, which is a variable scoped to within the function. `qux = argument2` assigns the value of `argument2` ("hi") to `qux`, which is your global `qux` variable. – deceze Aug 23 '22 at 08:49
  • the big difference here is that you pass a reference to an object with foo, while you pass a value with qux more -> https://codeburst.io/explaining-value-vs-reference-in-javascript-647a975e12a0 – zergski Aug 23 '22 at 08:50
  • 2
    Maybe the biggest misunderstanding you have is that you just pass *values* into functions, **not "variables names"**. And you assign exactly to the variables you're assigning to, not double-indirectly to values of variables interpreted as variable names. – deceze Aug 23 '22 at 08:53
  • ^ this is indeed my biggest misunderstanding, many thanks @deceze that immediately clarifies things! – Brucie Aug 23 '22 at 11:01

2 Answers2

1
function bar(argument1, argument2) {
  argument1.a = 'hi';
  argument2 = 'hi';
}

argument1.a = ... mutates whatever object is held by argument1 (whatever was passed as the first argument to bar). The change will be seen by anyone else who holds a reference to the same object.

argument2 = ... assigns a new value to the variable argument2. It does not influence whatever was assigned to the variable before, it simply says "the name argument2 now refers to this ... value". This variable has been declared as a parameter of bar, and thus is scoped to bar, and changes to it will only be seen within bar, because the variable only exists within bar.

let qux = 'hello';

function bar(..., argument2) {
  ...
  qux = argument2;
}

qux = ... assigns a new value to the variable qux. This variable has been declared in the global scope outside the function, so this alters that variable outside the function.

bar(foo, qux);

This calls bar and passes the values that foo and qux refer to as arguments. It does not pass "the variables foo and qux", it passes their values. If the value is mutable and is mutated inside the function (as is the case for foo), you'll see that mutation afterwards if you look at foo. If the value is not mutable (as is the case for qux), then there's nothing the function can do to that value that would be visible afterwards.

Again, do not confuse this with overwriting qux with a new value in your second case.

deceze
  • 510,633
  • 85
  • 743
  • 889
-2

the big difference here is that you pass a reference to an object with foo, while you pass a value with qux

changing an argument that recieves a primitive value acts as a new variable in the function scope, while a passed reference 'points' to the original object

more -> https://codeburst.io/explaining-value-vs-reference-in-javascript-647a975e12a0

zergski
  • 793
  • 3
  • 10
  • 1
    There is no difference between passing a primitive and an object, the difference is simply that you can't mutate a primitive. – deceze Aug 23 '22 at 08:58
  • isn't it exactly what I said? with the exception of symbol, primitives are passed by value and are stored in the stack with the value directly (stack: foo=44) and thus are immutable. while objects are stored in the heap by reference from the stack(stack: obj -> heap -> {name: 'bar'}) – zergski Aug 23 '22 at 09:59
  • 1
    There needs to be no difference in where they're stored. Primitives are immutable *because they don't have any methods to mutate them*. You can't do `42.setValue(69)`. It simply doesn't exist, thus immutable values cannot be mutated, regardless of whether they're on the heap, stack or elsewhere. – deceze Aug 23 '22 at 10:00
  • yet its how the data is stored that defines if something can have a 'setValue(69)' method or be a primitive... you are very wrong about there being no difference betweer primitive and reference values... – zergski Aug 23 '22 at 10:07
  • 1
    Whether it's stored on the heap or stack is an irrelevant implementation detail. The `String` type has no methods that would allow altering of the value of a `String` instance. *That's* what makes a `String` immutable. And because it has that property, it may be implemented a certain way behind the scenes, but that's entirely secondary. Maybe the implementation concern dictated the immutable design or vice versa, but as far as userland Javascript code is concerned, you can't mutate a `String` because it doesn't have methods that mutate it. – deceze Aug 23 '22 at 10:10
  • It's a design decision by the language designer(s). *If* they wanted to have mutable strings, or `42.setValue(69)`, they *could* have implemented that if they wanted to, and stored the values on the heap accordingly as necessary. But they decided not to have mutable strings nor numbers, thus didn't implement them. Immutable types are immutable because they've been designed to not be mutable. – deceze Aug 23 '22 at 10:21
  • and what defines a Number instance? everything is made and limited by memory manipulation and managment, that's just how things work. I understand that you're saying that someone decided this way so it is, what you're missing is that there are reasons why those design decisions were made and that when they were, they had to manage & store those types differently. it's good practice to understand why instead of just saying it's because someone willed it so. – zergski Aug 23 '22 at 10:31
  • I understand that you don't do mutable strings, because it's a headache with allocating memory. I'm saying that's all fairly irrelevant from the point of view of a Javascript developer. Strings aren't immutable because they're stored on the stack or whatever; they're immutable because the language doesn't give you anything to mutate them (which is because the designer decided to implement it this way because it's a headache to do it otherwise). Immediate explanations first, obscure technical details second. – deceze Aug 23 '22 at 11:01