When we assign a variable to another variable (let a = b), the engine does not look inside the data. It blindly copies the Stack Slot.
When we assign a Primitive, the engine copies the actual value.
let a = 10;
let b = a; // Copy the value 10
b = 20; // a is still 10When we assign an Object, the engine copies the Memory Address stored in stack slot, not the Heap data.
Aliasing.let user1 = { name: "Singh" }; // Address: 0x001
let user2 = user1; // Copy the Address 0x001Because objects live in the Heap, comparison operators do not look at the properties inside the object. They look at the addresses stored in the Stack.
Two objects are only equal if they point to the same physical memory address.
{} === {} is false because each literal creates a new unique address in the Heap.objA === objB is true only if they share the same reference.==) vs. Triple (===) EqualsThe comparison behavior changes fundamentally depending on whether the engine stays in the Stack or triggers a Coercion routine into the Heap.
A. Triple Equals (Strict Equality: ===)
false immediately. If both are objects, it checks if they occupy the same Heap slot.B. Double Equals (Abstract Equality: ==)
===. It compares addresses. No content checking occurs.ToPrimitive algorithm. It attempts to convert the object to a primitive (via .toString() or .valueOf()) to compare values instead of addresses.const arr = [42];
const num = 42;
// Scenario 1: Object vs Object
console.log([42] == [42]); // false (Unique addresses in Heap)
// Scenario 2: Object vs Primitive (Coercion)
// arr.toString() becomes "42", then coerced to Number 42
console.log(arr == num); // trueAliasing is dangerous because it might lead to unintended result. We can modify a variable in File A, and it accidentally updates a variable in File B because they share the same Heap Address.
Mutation (Modifying the Heap):
const user = { name: "Singh" };
user.name = "Astra"; // Allowed! The Stack pointer didn't change.Reassignment (Modifying the Stack):
let user = { name: "Singh" };
user = { name: "New" }; // The old link is gone.const MythMany developers believe const makes an object immutable. It does not.
const creates an Immutable Binding. It locks the Stack Slot. We cannot Reassign the variable to a new address.Since assignment (=) only creates an alias, how do we actually clone an object?
...)ES6 introduced the Spread syntax.
Assignment Trap: For each property, it performs a standard Assignment.
user.address.city), those nested objects are still copied by reference.let original = {
name: "Singh",
meta: { role: "Admin" },
};
let copy = { ...original };
copy.name = "Clone"; // Safe (Original is still "Singh")
copy.meta.role = "User"; // DANGER! Original.meta.role becomes "User"To fully clone a nested tree, we need a Deep Copy.
The JSON Hack (Legacy):
JSON.parse(JSON.stringify(obj))Functionor undefined, the engine ignores the entire key-value pair,it is removed from the string.Date objects into ISO Strings (e.g., "2025-12-19T...")..getFullYear() or .setHours().structuredClone() (Modern Standard):
let deepCopy = structuredClone(original);
// Completely safe. No shared references.| Operation | Syntax | Stack Action | Heap Action | Result |
|---|---|---|---|---|
| Assignment | b = a | Copy Slot | None | Alias (Shared Ref) |
| Reassignment | a = {} | Update Slot | Create new Obj | Broken Link |
| Mutation | a.x = 1 | None | Update Obj | Side Effect |
| Shallow Copy | {...a} | Create new Ref | Copy Layer 1 | Mixed (Shared Nested) |
| Deep Copy | structuredClone | Create new Ref | Recursive Copy | True Clone |