Understanding Shallow and Deep Copying of Objects in JavaScript

// Assigning a value from a to b
let a = 12;
let b = a;

This method works for primitive types. What happens if a is an object? Let's examine what occurs in memory:

Declaring a = 12 allocates a space in the stack. When a is assigned to b, another space is created in the stack, and b holds the same value as a.

If a is an object, what happens in memory? Consider the following example:

let a = {};
let b = a;

Objects are stored in the heap, while the stack holds their reference addresses. This kind of assignment only copies the reference, not the actual object. So, how should objects be copied? The idea is to create a new object with the same properties and methods as the original. Here's a function to do that:

function copy(obj){
  // Return primitives and functions directly
  if(!(obj instanceof Object) || typeof obj === 'function') return obj;

  let newObj = {};
  if(obj instanceof Array) newObj = [];

  for(let p in obj){
    newObj[p] = obj[p];
  }
  return newObj;
}

let p = {
  name: 'bob',
  friends: ['jack', 'rose']
};
let p2 = copy(p);
console.log(p2);

The copy function checks if the input is a primitive or a function and returns it diretcly. It creates a new object and iterates through the properties of the original object, assigning them to the new one. However, this approach has a problem. Consider the following code:

p2.friends.push('lily');
console.log(p2.friends);//["jack", "rose", "lily"]
console.log(p.friends);//["jack", "rose", "lily"]

Modifying p2.friends also changes p.friends. This is because the friends property is a reference type, and the assignment only copies the address. This is known as shallow copying. To avoid this, we need to implement deep copying, which recursively copies all nested properties:

// Deep copy function
function deepCopy(obj){
  // Return primitives and functions directly
  if(!(obj instanceof Object) || typeof obj === 'function') return obj;

  let newObj = {};
  if(obj instanceof Array) newObj = [];

  for(let p in obj){
    // Recursively copy nested objects
    newObj[p] = deepCopy(obj[p]);
  }
  return newObj;
}

let p = {
  name: 'bob',
  friends: ['jack', 'rose']
};
let p2 = deepCopy(p);

p2.friends.push('lily');
console.log(p2.friends);//["jack", "rose", "lily"]
console.log(p.friends);//["jack", "rose"]
console.log(p.friends == p2.friends);//false

JavaScript provides Object.assign() for shallow copying:

let p3 = Object.assign({}, p);
console.log(p3.friends == p.friends);//true

In JavaScript inheritacne, Object.create() behaves similarly to shallow copying but establishes an inheritance relationship. In contrast, Object.assign() creates an independent object. For example:

let p4 = Object.create(p);
console.log(p4.__proto__ === p);//true
console.log(p3.__proto__ === p);//false

Tags: javascript object copying shallow copy deep copy

Posted on Sat, 30 May 2026 21:40:20 +0000 by RootKit