DEV Community

Raju Saha
Raju Saha

Posted on

Shallow Copy vs Deep Copy in JavaScript

When working with objects in JavaScript, understanding the difference between shallow copy and deep copy is crucial. This knowledge helps avoid unexpected behavior, especially when dealing with nested objects.

Shallow Copy

A shallow copy duplicates the top level of an object but does not recursively copy nested objects. Instead, it retains references to the original nested objects. Here are some common methods for creating shallow copies: Object.assign() and the spread operator {...object}.

Example

Code snippet of the shallow copy
In this example, changing the fullName in narutoCopy does not affect the original naruto object.

However, with nested objects, a shallow copy only copies the references:

Nested Shallow Copy Code Snippet

In this case, both narutoDetails and narutoDetailsCopy have the same reference to the parent's object. Changing the father property in narutoDetailsCopy also changes it in narutoDetails.

Deep Copy

A deep copy duplicates an object along with all the objects it references, recursively. The easiest way to achieve this in JavaScript is by using JSON.parse(JSON.stringify(object)). For more complex scenarios, libraries like lodash provide deep copy functions.

Example

Deep Copy Code Snippet

In this example, borutoCopyis a completely independent copy of boruto. Changes to borutoCopydo not affect boruto.

Top comments (5)

Collapse
 
jonrandy profile image
Jon Randy πŸŽ–οΈ • Edited

The easiest way to achieve this in JavaScript is by using JSON.parse(JSON.stringify(object))

Not really. Using the built in structuredClone is even easier, and works better:

const copy = structuredClone(object)
Enter fullscreen mode Exit fullscreen mode
Collapse
 
jahid6597 profile image
MD. JAHID HOSSAIN

JSON.parse(JSON.stringify(object)) efficiently creates a copy of simple objects by converting them to a JSON string and back, but loses complex data types like NaN, Set and Map. structuredClone preserves complex data types and handles NaN and Set, but doesn't support functions or symbols and may not be universally available.

Let's take an example:

const original = {
  value: undefined,
  infinity: Infinity,
  nan: NaN,
  date: new Date(),
  regExp: /hello/i,
  buffer: new ArrayBuffer(10),
  nested: {
    set: new Set([1, 2, 3]),
    map: new Map([["key1", "value1"], ["key2", "value2"]])
  },
  //   func: function() { return "Hello"; },
  //   symbol: Symbol('sym')
};
Enter fullscreen mode Exit fullscreen mode

original object containing various data such as undefined, Infinity, NaN, Date, RegExp, ArrayBuffer, Set and Map. Properties func and symbol are commented.

const clonedJSON = JSON.parse(JSON.stringify(original));
console.log(clonedJSON);
// {
//   "infinity": null,
//   "nan": null,
//   "date": "2024-06-24T07:08:01.362Z",
//   "regExp": {},
//   "buffer": {},
//   "nested": {
//     "set": {},
//     "map": {}
//   }
// } 
Enter fullscreen mode Exit fullscreen mode

JSON.parse(JSON.stringify(object))

  • Loses undefined, Infinity, NaN, functions, symbols, RegExp, Date, Set, Map, ArrayBuffer, and other non-JSON data types.
  • Suitable for simple, plain objects without complex data types or structures.
const clonedStructured = structuredClone(original);
console.log(clonedStructured);
// {
//   "value": undefined,
//   "infinity": null,
//   "nan": null,
//   "date": "2024-06-24T07:08:01.362Z",
//   "regExp": {},
//   "buffer": {},
//   "nested": {
//     "set": {},
//     "map": {}
//   }
// } 
Enter fullscreen mode Exit fullscreen mode

structuredClone

  • Preserves most data types including undefined, Infinity, NaN, RegExp, Date, Set, Map, ArrayBuffer.
  • Does not clone functions or symbols.
  • Suitable for complex objects and structures requiring accurate deep copying.

Case #1

console.log(clonedJSON.nan); // null
// `clonedJSON.nan` will be `null` because `NaN` cannot be represented in JSON and is lost during the stringify operation

console.log(clonedStructured.nan); // NaN
// `clonedStructured.nan` remains `NaN` because `structuredClone` is designed to handle complex JavaScript objects and can correctly preserve `NaN` during the cloning process.
Enter fullscreen mode Exit fullscreen mode

Case #2

console.log(clonedJSON.nested.set); // {}
// `clonedJSON.nested.set` will be `{}` because the `Set` is lost during the `stringify` operation.

console.log(clonedStructured.nested.set); // Set (3) {1, 2, 3}
// `clonedStructured.nested.set` remains a `Set` object containing the same values `[1, 2, 3]` as in the `original` object.
Enter fullscreen mode Exit fullscreen mode
Collapse
 
rajusaha profile image
Raju Saha

@jahid6597
Thanks 😊 As I am still learning and was not aware about the structuredClone

Collapse
 
rajusaha profile image
Raju Saha

@jonrandy
Thanks 😊

Collapse
 
sudhirkumar1003 profile image
Sudhir Kumar • Edited

Thanks you. Wasn't aware about this fn.