What About Coding
By himanshu123JavaScript

Shallow Copy and Deep Copy in Javascript

Shallow Copy vs Deep Copy in JavaScript

Introduction

  • Shallow copy: duplicates only the top level of an object or array. Any nested objects/arrays inside are still shared by reference between the original and the copy โ€” they aren't truly duplicated.
  • Deep copy: duplicates everything, including nested structures, so the original and the copy share no references at all.

By default, assigning one JavaScript object to another variable just copies a reference (a pointer to the same spot in memory), not the actual data.

Illustrating the problem:

let person = { name: "Alice" };
let alias = person;

alias.name = "Bob";

console.log(person); // { name: "Bob" }
console.log(alias);  // { name: "Bob" }

Both variables point at the same object, so changing one changes the other. This is "copy by reference," and it's usually not what you want when you intend to create an independent copy.

Shallow Copy

Option 1: Object.assign()

let original = { name: "Alice" };
let copy = Object.assign({}, original);

copy.name = "Carol";

console.log(original); // unaffected
console.log(copy);     // updated

Option 2: Spread syntax

let original = { name: "Alice" };
let copy = { ...original, role: "Engineer" };

copy.name = "Carol";

console.log(original);
console.log(copy);

Limitation of shallow copy

It only duplicates the first level of properties. Any nested object inside stays shared.

const person = {
  name: "Dave",
  city: "Delhi",
  education: {
    school: "Central High",
    college: "IIT",
  },
};

let clone = Object.assign({}, person);

clone.city = "Mumbai";           // works independently
clone.education.college = "NIT"; // also changes person.education.college!

console.log(person);
console.log(clone);

The top-level city field copies fine, but education.college is shared, so editing it on the clone also changes the original.

Deep Copy

Method 1: JSON round-trip

Convert the object to a JSON string, then parse it back โ€” this produces a brand-new structure with no shared references.

const person = {
  name: "Dave",
  city: "Delhi",
  education: {
    school: "Central High",
    college: "IIT",
  },
};

let clone = JSON.parse(JSON.stringify(person));

clone.city = "Mumbai";
clone.education.college = "NIT";

console.log(person); // untouched
console.log(clone);  // fully independent

Limitation: the JSON round-trip silently drops anything JSON can't represent โ€” functions and Date/time values included in the object won't survive the conversion.

const person = {
  name: "Dave",
  city: "Delhi",
  education: { school: "Central High", college: "IIT" },
  greet: function () {
    console.log("Hi, I'm", this.name);
  },
};

let clone = JSON.parse(JSON.stringify(person));
// clone.greet is now undefined โ€” the function was lost

Method 2: Lodash's cloneDeep

Lodash is a popular JS utility library with many helper functions, including a robust deep-clone that preserves things JSON can't, like functions.

// include lodash via CDN or npm, then:
let clone = _.cloneDeep(person);

console.log(person === clone); // false โ€” separate objects

clone.name = "Eve";
clone.education.college = "NIT";

console.log(person); // untouched
console.log(clone);  // independent, and greet() still works

Alternative: Prototype-based sharing (__proto__)

Rather than copying, you can link one object's prototype to another so it inherits shared behavior/properties while still being able to override them locally.

const base = {
  name: "Himanshu",
  city: "Ranchi",
  describe() {
    console.log(`${this.name} from ${this.city}`);
  },
};

const other = {
  name: "Shekhar",
  describe() {
    console.log(`${this.name} from ${this.city}`);
  },
};

other.__proto__ = base;
other.city = "Bengaluru"; // own property, doesn't affect base

console.log(base.city);  // "Ranchi"
console.log(other.city); // "Bengaluru"

Share

More recent posts

View all