Primitives are copied by value; objects are shared by reference. Almost every “why did my data change?” bug comes from this.
Copying a primitive
let a = 10;
let b = a; // b gets its own copy of the value
b = 20;
console.log(a, b);10 20Copying an object reference
const original = { score: 10 };
const alias = original; // copies the *reference*, not the object
alias.score = 99;
console.log(original.score);
console.log(original === alias);99
true| Primitives | Objects (incl. arrays, functions) | |
|---|---|---|
| Stored as | The value itself | A reference to a heap object |
| Assignment copies | The value | The reference |
=== compares | Values | Identity (same object?) |
| Mutable? | No — immutable | Yes |
Equality compares identity for objects
console.log("abc" === "abc");
console.log({ a: 1 } === { a: 1 });
console.log([1, 2] === [1, 2]);
const arr = [1, 2];
console.log(arr === arr);true
false
false
truePassing to functions: always by value (of the reference)
JavaScript is pass-by-value. For objects the value being passed is a reference — so a function can mutate the caller's object, but reassigning the parameter never affects the caller.
function mutate(obj) {
obj.touched = true; // changes the shared object
}
function reassign(obj) {
obj = { replaced: true }; // only rebinds the local parameter
}
const data = {};
mutate(data);
reassign(data);
console.log(data);{ touched: true }Primitives are immutable
const s = "hello";
const upper = s.toUpperCase(); // returns a NEW string
console.log(s, upper);
const t = "cat";
try {
t[0] = "b"; // strings can't change in place
} catch (e) {
console.log(e.name + ": " + e.message);
}
console.log(t);hello HELLO
TypeError: Cannot assign to read only property '0' of string 'cat'
catIn strict mode (every ES module) the assignment throws; in a sloppy script it is silently ignored. Either way the string never changes.
Is JavaScript pass-by-reference?