What does this mutate-vs-reassign snippet print, and why?
Predict each console.log and explain the difference between mutating an object through a parameter and reassigning the parameter, and between a parameter and an outer-scope variable.
let x = { a: 1, b: 2 };
function fn1(x) { x.a = 5; } // mutates via parameter
function fn2() { x.a = 5; } // mutates outer x
function fn3(x) { x = 5; } // reassigns local parameter
function fn4() { x = 5; } // reassigns outer x
fn1(x); console.log(x);
fn3(x); console.log(x);
fn4(); console.log(x);
Determine the output and explain it.
{ a: 5, b: 2 }, then { a: 5, b: 2 }, then 5. JavaScript passes the object's reference by value: fn1 mutates the shared object through the parameter, so the change is visible outside. fn3 only reassigns its local parameter to 5 — that rebinds the local name, leaving the outer object untouched. fn4 reassigns the outer x itself (no parameter shadows it), so x becomes the primitive 5.
- ✗Thinking reassigning a parameter (
x = 5) changes the caller's variable like property mutation does - ✗Calling JavaScript pure pass-by-reference for objects — it passes the reference by value
- ✗Assuming a parameter named like an outer variable shares the same binding
- →Why does mutating a property show outside the function but reassigning the parameter does not?
- →How does
fn4reach the outerxwhilefn3cannot?
Solution
Output: { a: 5, b: 2 }, { a: 5, b: 2 }, 5.
let x = { a: 1, b: 2 };
function fn1(x) { x.a = 5; }
function fn3(x) { x = 5; }
function fn4() { x = 5; }
fn1(x); console.log(x); // { a: 5, b: 2 } — mutation through the reference
fn3(x); console.log(x); // { a: 5, b: 2 } — parameter reassignment is local
fn4(); console.log(x); // 5 — reassigns the outer x itself
How it works
JavaScript passes arguments by value, but for an object that value is a reference. So fn1, accessing x.a, follows the reference to the same object and changes its property — the change is visible outside.
fn3 does x = 5: this assignment rebinds the local parameter to a new value, and the caller's original reference is untouched, so the object stays { a: 5, b: 2 }. fn4 has no parameter, so its x is the outer variable itself; reassigning it makes x the primitive 5. </content>