How do references differ from values in JavaScript?
Primitives are copied by value, and objects are copied by reference. When you assign a primitive, the new variable holds its own copy of the value, so changing one never affects the other. When you assign an object, the new variable holds a reference to the same object, so both names point at one piece of memory.
const first = { count: 1 };
const second = first; // both names point at the same object
second.count = 2;
console.log(first.count); // 2 - the change shows through both names
console.log(first === second); // true - same reference
// Primitives behave differently.
let a = 5;
let b = a;
b = 10;
console.log(a); // 5 - unchangedThe mental model that makes this click is that a variable is a label pointing at a value. For a primitive, the value itself is small and immutable, so the label is copied along with the value. For an object, the object lives somewhere else in memory and the label points at it, so copying the label copies the pointer, not the thing it points at.
Function parameters follow the same rule. Passing a primitive passes a copy of the value, so the callee cannot change the caller variable. Passing an object passes the reference, so any mutation inside the function is visible to the caller. This is why a function that mutates its argument is a design smell, and why functions that need to modify data usually return a new value instead.
One exception worth knowing. The null value and the value that stands for a missing binding are primitives, so they behave by value, and so do strings, numbers and booleans even though they have methods on them. The methods live on a wrapper prototype, not on the value, so nothing is shared.