How to Clone a JavaScript Object: A Comprehensive Guide

Cloning a JavaScript object means creating an exact copy of it. This is useful when you want to modify an object without affecting the original one. In this article, we’ll explore different methods to clone objects in JavaScript, from simple shallow copies to more complex deep copies.

Table of Contents

Why Clone Objects?

When you assign an object to another variable in JavaScript, you’re not creating a copy. Instead, both variables point to the same object in memory. If you modify one, the other changes as well. This can lead to unintended side effects in your code. Cloning creates a new object with the same properties, ensuring that modifications to one don’t affect the other.

const original = { name: 'Alice', age: 30 };
const reference = original;
reference.name = 'Bob';

console.log(original.name); // Output: Bob

In this example, original and reference point to the same object. Changing reference.name also changes original.name.

Shallow Copy vs. Deep Copy

  • Shallow Copy: Creates a new object and copies the references of the original object’s properties. If the properties are objects themselves, both the original and the copy will reference the same nested objects.
  • Deep Copy: Creates a new object and recursively copies all nested objects, ensuring that the original and the copy are completely independent.
const original = { name: 'Alice', address: { city: 'London' } };
const shallowClone = Object.assign({}, original);
shallowClone.address.city = 'Paris';

console.log(original.address.city); // Output: Paris
console.log(shallowClone.address.city); // Output: Paris

Here, both original and shallowClone share the same address object.

Methods to Clone JavaScript Objects

Using Object.assign()

Object.assign() is a built-in method that copies all enumerable properties from the source object(s) to the target object. It creates a shallow copy.

const original = { a: 1, b: 2 };
const clone = Object.assign({}, original);

original.a = 3;
console.log(clone.a); // Output: 1

Using the Spread Operator

The spread operator (...) can also be used to create a shallow copy of an object.

const original = { a: 1, b: 2 };
const clone = { ...original };

original.a = 3;
console.log(clone.a); // Output: 1

Using JSON.parse() and JSON.stringify()

This method converts the object to a JSON string and then parses it back into a new object. It creates a deep copy but has limitations:
– It doesn’t copy functions.
– It doesn’t handle circular references.
– It converts undefined values to null.

const original = { name: 'Alice', address: { city: 'London' } };
const clone = JSON.parse(JSON.stringify(original));

clone.address.city = 'Paris';
console.log(original.address.city); // Output: London
console.log(clone.address.city); // Output: Paris

Deep Copy with a Custom Function

For more complex objects with nested structures, you can write a custom function to perform a deep copy.

function deepClone(obj) {
  if (typeof obj !== 'object' || obj === null) {
    return obj;
  }

  const clone = Array.isArray(obj) ? [] : {};

  for (const key in obj) {
    if (obj.hasOwnProperty(key)) {
      clone[key] = deepClone(obj[key]);
    }
  }

  return clone;
}

const original = { a: 1, b: { c: 2 } };
const clone = deepClone(original);

clone.b.c = 3;
console.log(original.b.c); // Output: 2
console.log(clone.b.c); // Output: 3

Using a Library like Lodash

Lodash provides a utility method _.cloneDeep() for creating deep copies of objects.

const _ = require('lodash');

const original = { a: 1, b: { c: 2 } };
const clone = _.cloneDeep(original);

clone.b.c = 3;
console.log(original.b.c); // Output: 2
console.log(clone.b.c); // Output: 3

Comparison of Cloning Methods

MethodShallow CopyDeep CopyHandles FunctionsHandles Circular References
Object.assign()YesNoNoNo
Spread OperatorYesNoNoNo
JSON.parse() / JSON.stringify()NoYesNoNo
Custom FunctionNoYesYesYes (if implemented)
Lodash _.cloneDeep()NoYesYesYes

Frequently Asked Questions

Q1: What’s the difference between shallow and deep copy?

  • Shallow Copy: Creates a new object but references the same nested objects as the original.
  • Deep Copy: Creates a new object with entirely new nested objects, ensuring independence between the original and the copy.

Q2: Which method should I use for most cases?

For most cases, Object.assign() or the spread operator is sufficient for shallow copies. For deep copies, consider using JSON.parse()/JSON.stringify() or a library like Lodash if you need to handle functions or circular references.

Q3: Can I clone an array using these methods?

Yes, the same methods can be used to clone arrays. For example:

const original = [1, 2, 3];
const clone = [...original];

Q4: What about objects with methods?

Methods are not copied by Object.assign(), the spread operator, or JSON.parse()/JSON.stringify(). For objects with methods, consider using a custom deep clone function or a library like Lodash.

Q5: How do I handle circular references?

Circular references (where an object refers back to itself) can cause issues in deep cloning. Custom deep clone functions or libraries like Lodash can handle this if implemented properly.

Conclusion

Cloning objects in JavaScript is essential to avoid unintended side effects when modifying objects. The method you choose depends on whether you need a shallow or deep copy and the complexity of the object you’re cloning. For simple cases, Object.assign() or the spread operator works well. For more complex objects, consider using JSON.parse()/JSON.stringify() or a library like Lodash.

Index
Scroll to Top