Deep‑Cloning vs. Shallow‑Cloning in JavaScript

Hero image for Deep‑Cloning vs. Shallow‑Cloning in JavaScript. Image by Philipp Katzenberger.
Hero image for 'Deep‑Cloning vs. Shallow‑Cloning in JavaScript.' Image by Philipp Katzenberger.

When working with objects in JavaScript, we often need to create copies. However, not all copies behave the same way. Some methods copy only the toplevel properties, whilst others create a fully independent duplicate. If we do not use the right approach, we can run into unintended side effects where changing one object also changes another.

This is where shallow cloning and deep cloning come into play. In this article, I explore how they work, the best methods for each, and when to use them to avoid unnecessary bugs.


What is Shallow‑Cloning?

A shallow clone creates a new object with copies of the original's toplevel properties. However, if the object contains nested objects or arrays, those remain referenced rather than copied. This means changes to nested structures affect both the original and the clone.

An Example of Shallow‑Cloning

The spread operator (...) is a common way to create a shallow clone of an object:

const original = { name: "Ellie", details: { age: 30 } };const shallowClone = { ...original };shallowClone.name = "Bob";shallowClone.details.age = 40;console.log(original.name);  // "Ellie" (unchanged)console.log(original.details.age);  // 40 (changed)

Here, shallowClone.name is independent of the original; however, shallowClone.details still points to the same object as original.details. This means modifying shallowClone.details.age also updates original.details.age.

Other Ways to Create a Shallow Clone

Apart from the spread operator, we can also do something like this:

const shallowClone1 = Object.assign({}, original);const shallowClone2 = structuredClone(original, { transfer: [] });  // For transferable objects

Both methods behave similarly, copying only the first level of properties whilst keeping references to nested objects.

When Should We Use Shallow Cloning?

Shallow cloning is ideal when:

  • The object only contains primitive values.
  • We need a quick copy without duplicating deeply nested structures.
  • The nested objects should remain shared between copies.

If we need a completely separate object, including its nested properties, we need a deep clone.


What is Deep‑Cloning?

A deep clone creates a fully independent copy of an object, including all nested objects and arrays. Changes to the cloned object do not affect the original, and vice versa.

An Example of Deep‑Cloning

const original = { name: "Ellie", details: { age: 30 } };const deepClone = JSON.parse(JSON.stringify(original));deepClone.details.age = 40;console.log(original.details.age);  // 30 (unchanged)

Since we have created a new structure, modifying deepClone.details.age does not affect original.details.age.

Better Ways to Deep‑Clone Objects

Whilst JSON.parse(JSON.stringify(...)) works, it has limitations:

  • It does not copy functions, Dates, Maps, or Sets.
  • It ignores undefined values.

A better approach is using structured cloning or a deepcloning utility like Lodash's cloneDeep.

Using structuredClone (Modern JavaScript Method)

const deepClone = structuredClone(original);

This method correctly handles most data types and is natively supported in modern browsers.

Using Lodash's cloneDeep

In situations where you might need to support browsers that predate structuredClone, Lodash offers an easytouse method to achieve much the same:

import cloneDeep from "lodash.clonedeep";const deepClone = cloneDeep(original);

This works by recursively copying all properties of an object, ensuring that nested structures, arrays, and special types like Date, Map, and Set are fully duplicated, rather than referenced. This makes it the most reliable deepcloning method in JavaScript, and avoids issues found in simpler approaches like JSON.parse(JSON.stringify(obj)), or potential browser incompatibility with structuredClone.


Performance Considerations

Deep cloning is more computationally expensive than shallow cloning, as it creates entirely new copies of nested structures. If an object is large or deeply nested, this can lead to significant performance overhead.

Shallow vs. Deep Cloning Performance

We can see the performance differences very easily by setting up a simple test:

const obj = { nested: { value: 42 } };console.time("Shallow Clone");for (let i = 0; i < 1000000; i++) {  const clone = { ...obj };}console.timeEnd("Shallow Clone");console.time("Deep Clone");for (let i = 0; i < 1000000; i++) {  const clone = structuredClone(obj);}console.timeEnd("Deep Clone");

For small objects, the performance difference is minor. However, deep cloning can become significantly slower as objects grow larger.

When Should We Use Deep Cloning?

Deep cloning is useful when:

  • We need completely independent objects to avoid unwanted mutations.
  • The object contains nested structures that should not be shared.
  • We are working with immutable state updates in libraries like Redux.

For simple structures or when performance is a concern, shallow cloning is often a better choice.

Wrapping up

Choosing between shallow and deep cloning depends on what we are trying to achieve. If we only need a copy of toplevel properties, shallow cloning is fast and efficient. However, if we need to ensure that nested structures are fully independent, deep cloning is the safer approach.

Key Takeaways

  • Shallow cloning

    copies toplevel properties but keeps references to nested objects.
  • Deep cloning

    creates a fully independent copy of an object, including its nested structures.
  • The spread operator (

    ...) and Object.assign() perform shallow cloning.
  • structuredClone()

    and Lodash's cloneDeep() are the most reliable methods for deep cloning.
  • Deep cloning has performance costs

    , so it should only be used when necessary.

Understanding how these cloning methods work helps us write more predictable and bugfree code, making our applications easier to maintain.


Categories:

  1. Development
  2. Front‑End Development
  3. Guides
  4. JavaScript