What happens: Objects are stored by reference, not by value (unlike primitives)

Reference vs Value Copying:

1. Primitives - copied by value

javascript

let a = "hello";
let b = a; // copies the actual value
a = "world";
console.log(b); // "hello" (independent copy)

2. Objects - copied by reference

javascript

let user = { name: "John" };
let admin = user; // copies the reference, not the object
admin.name = "Pete";
console.log(user.name); // "Pete" (same object!)

Key Reference Behaviors:

1. Multiple variables point to same object

javascript

let obj1 = { value: 5 };
let obj2 = obj1;
let obj3 = obj1;
 
obj2.value = 10;
console.log(obj1.value); // 10 (all point to same object)
console.log(obj3.value); // 10

2. Object comparison compares references

javascript

let a = { name: "John" };
let b = { name: "John" }; // different objects
let c = a; // same reference
 
console.log(a == b);  // false (different objects)
console.log(a === b); // false (different objects)
console.log(a == c);  // true (same reference)
console.log(a === c); // true (same reference)

3. const objects can be modified

javascript

const user = { name: "John" };
user.name = "Pete"; // ✅ Works - modifying property
user.age = 30;      // ✅ Works - adding property
 
// user = {}; // ❌ Error - can't reassign the reference

Object Cloning Methods:

1. Shallow copy with Object.assign()

javascript

let user = { name: "John", age: 30 };
 
// Method 1: Object.assign
let clone1 = Object.assign({}, user);
 
// Method 2: Spread operator
let clone2 = { ...user };
 
clone1.name = "Pete";
console.log(user.name); // "John" (original unchanged)

2. Problem with nested objects (shallow copy issue)

javascript

let user = {
  name: "John",
  address: { city: "NYC" }
};
 
let clone = { ...user };
clone.address.city = "LA";
console.log(user.address.city); // "LA" (nested object still shared!)

3. Deep copy with structuredClone()

javascript

let user = {
  name: "John", 
  address: { city: "NYC" }
};
 
let clone = structuredClone(user);
clone.address.city = "LA";
console.log(user.address.city); // "NYC" (truly independent!)

Interview Gotchas:

javascript

// Gotcha 1: Object comparison
let a = {};
let b = {};
console.log(a === b); // false (different objects!)
 
// Gotcha 2: Function parameters
function changeName(obj) {
  obj.name = "Changed";
  obj = { name: "New Object" }; // doesn't affect original
}
let user = { name: "John" };
changeName(user);
console.log(user.name); // "Changed" (not "New Object")
 
// Gotcha 3: Array of objects
let users = [{ name: "John" }, { name: "Jane" }];
let copy = [...users]; // shallow copy!
copy[0].name = "Pete";
console.log(users[0].name); // "Pete" (objects still shared!)
 
// Gotcha 4: const with nested objects
const data = { user: { name: "John" } };
data.user.name = "Pete"; // ✅ Works
data.user = { name: "New" }; // ✅ Works (changing property)
// data = {}; // ❌ Error (reassigning const)
 
// Gotcha 5: structuredClone limitations
structuredClone({
  func: function() {}, // ❌ Error - can't clone functions
  date: new Date(),    // ✅ Works
  regex: /abc/         // ✅ Works
});

Quick Decision Tree:

  • Need independent copy? → Use cloning
  • Nested objects? → Use structuredClone()
  • Simple objects? → Use {...obj} or Object.assign()
  • Has functions? → Manual cloning or accept shallow copy

Bottom line: Objects share references! Use === to check if same object, cloning methods to create independent copies. Watch out for nested objects in shallow copies!


How Object Parameters Work in Functions:

When you pass an object to a function:

  1. The reference gets copied (not the object itself)
  2. The parameter becomes a local variable that holds a copy of the reference
  3. Both the original variable and parameter point to the same object

Visual Explanation:

javascript

let user = { name: "John" };  // user holds reference to object
 
function changeName(obj) {     // obj gets a COPY of the reference
  // Now both 'user' and 'obj' point to the SAME object
  
  obj.name = "Changed";        // ✅ Modifies the shared object
  obj = { name: "New Object" }; // ❌ Only changes local 'obj' reference
}
 
changeName(user);

What happens step by step:

javascript

// Step 1: Before function call
user → { name: "John" }  // user points to object
 
// Step 2: Function call - reference is copied
user → { name: "John" } ← obj  // both point to same object
 
// Step 3: obj.name = "Changed"
user → { name: "Changed" } ← obj  // still same object, property modified
 
// Step 4: obj = { name: "New Object" }
user → { name: "Changed" }
obj → { name: "New Object" }  // obj now points to different object
 
// Step 5: Function ends, obj is destroyed
user → { name: "Changed" }  // original reference unchanged

Simple Rule:

You can modify the object’s properties, but you cannot change what the original variable points to

javascript

function test(obj) {
  // ✅ These work - modifying the shared object
  obj.name = "New Name";
  obj.age = 25;
  delete obj.city;
  
  // ❌ This doesn't affect original - reassigning local reference
  obj = { completely: "different" };
}
 
let user = { name: "John" };
test(user);
console.log(user); // { name: "New Name", age: 25 } - properties changed!

More Examples:

javascript

// Example 1: Property modification
function addAge(person) {
  person.age = 30; // ✅ Modifies shared object
}
let user = { name: "John" };
addAge(user);
console.log(user); // { name: "John", age: 30 }
 
// Example 2: Reassignment doesn't work
function replaceUser(person) {
  person = { name: "Pete", age: 25 }; // ❌ Only changes local reference
}
let user = { name: "John" };
replaceUser(user);
console.log(user); // { name: "John" } - unchanged!
 
// Example 3: Arrays work the same way
function addItem(arr) {
  arr.push("new"); // ✅ Modifies shared array
  arr = [1, 2, 3]; // ❌ Only changes local reference
}
let myArray = ["a", "b"];
addItem(myArray);
console.log(myArray); // ["a", "b", "new"]

Bottom line: Function parameters get a copy of the reference, so you can modify the object’s contents but can’t change what the original variable points to