How to Clone an Object in JavaScript

In JavaScript, objects are reference types, meaning when you assign or pass an object to another variable, it doesn't create a new copy but a reference to the original object. If you modify the new object, it will affect the original one too. To avoid this, you might need to clone an object, creating a separate copy that can be modified independently. In this post, we’ll explore various methods to clone objects in JavaScript.

Why Clone an Object?

Cloning an object is useful when you want to create a copy of an object that you can modify without affecting the original object. This is common in cases like:

  • Making changes to a configuration object without modifying the original settings.
  • Duplicating data in memory without changing the original source.
  • Safeguarding original objects from unintended mutations.

Types of Cloning: Shallow vs Deep Clone

Shallow Clone

A shallow clone only copies the object's immediate properties. If the object has nested objects or arrays, the references to those nested structures are copied rather than the actual content.

Deep Clone

A deep clone copies not only the object's properties but also the content of any nested objects or arrays, creating a fully independent copy.

Now, let’s look at different ways to clone an object in JavaScript.


1. Using the Spread Operator (...) for Shallow Cloning

The spread operator is a simple and concise way to clone an object. It copies the properties of the object into a new one.

Example:

const employee = {
  firstName: "Ramesh",
  lastName: "Fadatare",
  email: "ramesh.fadatare@gmail.com"
};

const clonedEmployee = { ...employee };

console.log(clonedEmployee);

Output:

{
  firstName: "Ramesh",
  lastName: "Fadatare",
  email: "ramesh.fadatare@gmail.com"
}

Note:

This is a shallow clone. If the object contains nested objects, only references to those nested objects are copied.


2. Using Object.assign() for Shallow Cloning

Another way to perform a shallow clone is by using the Object.assign() method. This method copies all enumerable properties from one or more source objects to a target object.

Example:

const employee = {
  firstName: "Ramesh",
  lastName: "Fadatare",
  email: "ramesh.fadatare@gmail.com"
};

const clonedEmployee = Object.assign({}, employee);

console.log(clonedEmployee);

Output:

{
  firstName: "Ramesh",
  lastName: "Fadatare",
  email: "ramesh.fadatare@gmail.com"
}

Like the spread operator, this method performs a shallow clone, meaning nested objects are not fully cloned.


3. Using JSON.parse() and JSON.stringify() for Deep Cloning

For a deep clone, you can use the JSON.parse() and JSON.stringify() combination. This approach serializes the object to a JSON string and then parses it back into a new object, effectively cloning all levels of nested objects.

Example:

const employee = {
  firstName: "Ramesh",
  lastName: "Fadatare",
  email: "ramesh.fadatare@gmail.com",
  address: {
    city: "Mumbai",
    zip: "400001"
  }
};

const clonedEmployee = JSON.parse(JSON.stringify(employee));

console.log(clonedEmployee);

Output:

{
  firstName: "Ramesh",
  lastName: "Fadatare",
  email: "ramesh.fadatare@gmail.com",
  address: {
    city: "Mumbai",
    zip: "400001"
  }
}

Limitations:

  • This method won’t work with functions, Date objects, or undefined values. They will be lost in the conversion process.
  • Circular references will cause an error (TypeError: Converting circular structure to JSON).

4. Using a Recursive Function for Deep Cloning

To overcome the limitations of the JSON method and handle deep cloning of objects with functions, arrays, and other complex data types, you can create a custom recursive function.

Example:

function deepClone(obj) {
  if (obj === null || typeof obj !== "object") {
    return obj;
  }
  
  const clone = Array.isArray(obj) ? [] : {};
  
  for (let key in obj) {
    if (obj.hasOwnProperty(key)) {
      clone[key] = deepClone(obj[key]);
    }
  }
  
  return clone;
}

const employee = {
  firstName: "Ramesh",
  lastName: "Fadatare",
  email: "ramesh.fadatare@gmail.com",
  address: {
    city: "Mumbai",
    zip: "400001"
  }
};

const clonedEmployee = deepClone(employee);

console.log(clonedEmployee);

Output:

{
  firstName: "Ramesh",
  lastName: "Fadatare",
  email: "ramesh.fadatare@gmail.com",
  address: {
    city: "Mumbai",
    zip: "400001"
  }
}

This custom deep clone function copies nested objects and arrays, ensuring the entire object is cloned without references to the original.


5. Using External Libraries (e.g., Lodash)

Libraries like Lodash provide utility functions to simplify complex tasks, including deep cloning. If you're working with large projects or need reliable deep cloning frequently, using a library like Lodash can save time and effort.

Example using Lodash:

const _ = require('lodash');

const employee = {
  firstName: "Ramesh",
  lastName: "Fadatare",
  email: "ramesh.fadatare@gmail.com",
  address: {
    city: "Mumbai",
    zip: "400001"
  }
};

const clonedEmployee = _.cloneDeep(employee);

console.log(clonedEmployee);

Lodash’s cloneDeep() method performs a deep clone, handling nested objects, arrays, and other complex data types without limitations.


Conclusion

Cloning objects in JavaScript is a common task, and the method you choose depends on your specific needs:

  • For shallow cloning, use the spread operator (...) or Object.assign().
  • For deep cloning (including nested objects), use JSON.parse() and JSON.stringify(), write a custom recursive function, or use a library like Lodash for the most robust solution.

Understanding when to perform a shallow or deep clone is key to managing objects in JavaScript without causing unwanted side effects.

Comments