Reference vs Value in JavaScript
Reference vs Value
One of the most confusing concepts for JavaScript beginners is how data is stored and copied.
Why does changing one variable sometimes affect another?
Why do primitives behave differently from objects?
The answer lies in value types and reference types.
In this article, you will learn:
what “passed by value” means
what “passed by reference” means
which data types follow which rule
common mistakes
how to avoid bugs
Let’s start.
Value Types in JavaScript
Value types are copied by value.
When you assign a value type to another variable, JavaScript creates a new copy.
Value (Primitive) Types
JavaScript has 7 primitive types:
numberstringbooleannullundefinedsymbolbigint
Example: Value Copy
let a = 10;
let b = a;
b = 20;
console.log(a); // 10
console.log(b); // 20
Here is what happens:
astores the value10bgets a copy of10Changing
bdoes not affecta
This is called pass by value.
Reference Types in JavaScript
Reference types are copied by reference.
Instead of copying the value, JavaScript copies the memory address.
Reference Types
objects
arrays
functions
Example: Reference Copy
let obj1 = { name: "Sam" };
let obj2 = obj1;
obj2.name = "Rahul";
console.log(obj1.name); // "Rahul"
console.log(obj2.name); // "Rahul"
Both variables point to the same object in memory.
So changes through one variable affect the other.
This is called pass by reference (more accurately, pass by sharing).
Why JavaScript Behaves This Way
Primitive values are small and simple.
Copying them is cheap.
Objects can be large and complex.
Copying them every time would be slow and memory-heavy.
So JavaScript shares the same reference instead.
Reference vs Value in Functions
Let’s see how this works when passing arguments to functions.
Passing a Value Type to a Function
function update(x) {
x = 50;
}
let num = 10;
update(num);
console.log(num); // 10
The function receives a copy of the value.
The original variable remains unchanged.
Passing a Reference Type to a Function
function update(user) {
user.age = 30;
}
const person = { age: 20 };
update(person);
console.log(person.age); // 30
The function can modify the original object.
Important Clarification
JavaScript is always pass-by-value.
For objects, the value being passed is the reference.
That is why this works:
function change(obj) {
obj = { name: "New" };
}
const user = { name: "Old" };
change(user);
console.log(user.name); // "Old"
Reassigning the parameter does not change the original reference.
Comparing Values and References
Value Comparison
10 === 10 // true
"hi" === "hi" // true
Reference Comparison
[1, 2] === [1, 2] // false
Because they are different objects in memory.
const a = [1, 2];
const b = a;
a === b // true
Same reference.
How to Copy Reference Types Properly
To avoid unintended side effects, you often need a copy.
Shallow Copy
Using Spread Operator
const original = { a: 1, b: 2 };
const copy = { ...original };
Using Object.assign()
const copy = Object.assign({}, original);
⚠️ Shallow copy only works one level deep.
Deep Copy
Using structuredClone() (Modern & Recommended)
const deepCopy = structuredClone(obj);
Using JSON (Limited)
const deepCopy = JSON.parse(JSON.stringify(obj));
Limitations:
loses functions
loses
undefinedfails for
Date,Map,Set
Common Mistakes
❌ Expecting arrays to copy automatically
const a = [1, 2];
const b = a;
b.push(3);
console.log(a); // [1, 2, 3]
❌ Comparing objects directly
{} === {} // false
❌ Forgetting nested references
const obj1 = { inner: { x: 1 } };
const obj2 = { ...obj1 };
obj2.inner.x = 5;
console.log(obj1.inner.x); // 5
Best Practices
✔ Understand which types are value vs reference
✔ Avoid mutating objects when possible
✔ Use shallow or deep copy intentionally
✔ Prefer immutable patterns in modern JS
✔ Be careful when passing objects to functions