What is Deep Copy in JavaScript?

What is Deep Copy in JavaScript?

Β·

6 min read

I recently wrote about Shallow Copy and I think with the shallow copy you should also understand about Deep Copy. So here is my latest post related to Deep Copy.


What is Deep Copy?

  • For objects and an array containing other objects or arrays, copying thee objects requires a deep copy. Otherwise, changes made to the nested references will change the data nested in the original object or array.
  • This is compared to a shallow copy, which works fine for an object or array containing only primitive values, but will fail for any object or array that has nested references to other objects or arrays.
  • Understanding the differences between == and === can help visually see the difference between shallow and deep copy, as the strict equality operator (===) shows that the nested references are the same:

Example

const nestedArray = [["πŸ˜‰", "πŸ™‚", "😎"]]
const nestedCopyWithSpeed = [...nestedArray]

console.log(nestedArray[0] === nestedCopyWithSpread[0]) // true -- Shallow Copy (Same reference)

// This is a hack to make a deep copy that is not recommended because it will often fail:
const nestedCopyWithHacl = JSON.parse(JSON.stringify(nestedArray))

console.log(nestedArray[0] === nestedCopyWithHack[0]) // false -- Deep Copy (Different references)

Let's see some methods for making a deep copy

Deep copy with lodash

The library lodash is the most common way JavaScript Developers make a deep copy. It is surprisingly easy to use:

import_from "lodash" // Import the entire lodash library

const nestedArray = [["πŸ˜‰", "πŸ™‚", "😎"]]

const notACopyWithEquals = nestedArray
console.log(nestedArray[0] === notACopyWithEquals[0]) // true

const shallowCopyWithSpread = [...nestedArray]
console.log(nestedArray[0] === shallowCopyWithSpread[0]) // true

const shallowCopyWithLodashClone = _.clone(nestedArray)
console.log(nestedArray[0] === shallowCopyWithLodashClone[0]) // true

const shallowCopyWithLodashCloneDeep = _.cloneDeep(nestedArray)
console.log(nestedArray[0] === shallowCopyWithLodashCloneDeep[0]) // false

nestedArray[0] = "🧐"
nestedArray[2][0] = "😑"

console.log(...nestedArray) // 🧐 ["πŸ™‚"]["😑"]
console.log(...notACopyWithEquals) // 🧐 ["πŸ™‚"]["😑"]
console.log(shallowCopyWithSpread) // ["πŸ˜‰"]["πŸ™‚"]["😑"]
console.log(...shallowCopyWithLodashClone) // ["πŸ˜‰"]["πŸ™‚"]["😑"]
console.log(...deepCopyWithLodashCloneDeep) //  ["πŸ˜‰"]["πŸ™‚"]["😎"]

Deep copy with Ramda

The functional programming library Ramda includes the R.clone() method, which makes a deep copy of an object or array.

import R from "ramda" // Import the entire ramda library

const nestedArray = [["πŸ˜‰", "πŸ™‚", "😎"]]

const notACopyWithEquals = nestedArray
console.log(nestedArray[0] === notACopyWithEquals[0]) // true

const shallowCopyWithSpread = [...nestedArray]
console.log(nestedArray[0] === shallowCopyWithSpread[0]) // true

const deepCopyWithRamdaClone = R.clone(nestedArray)
console.log(nestedArray[0] === deepCopyWithRamdaClone[0]) // false

nestedArray[0] = "🧐"
nestedArray[2][0] = "😑"

console.log(...nestedArray) // 🧐 ["πŸ™‚"]["😑"]
console.log(notACopyWithEquals) // 🧐 ["πŸ™‚"]["😑"]
console.log(shallowCopyWithSpread) // ["πŸ˜‰"]["πŸ™‚"]["😑"]
console.log(...deepCopyWithRamdaClone) // ["πŸ˜‰"]["πŸ™‚"]["😎"]

Read more - What Is Shallow Copy ?

Deep copy with JSON.parse/stringify

If your data fits the specifications, then JSON.parse followed by JSON.strigify will deep copy your object.

// Only some of these will work with JSON.parse() followed by JSON.stringify()

const samplwObject = {
    string: 'string', 
    number: 123
    boolean: false, 
    null: null,
    notANumber: NaN, // NaN values will be lost  (The  value will be forced to 'null')
    date: new Date('2020-12-31T23:59:59')
    undefined: undefined, // Undefined values will be completely lost, including the key containing the undefined value
    infinity: Infinity, // Infinity will be lost (the value will be forced to 'null' )
    regExp: /.*/, // regExp will be lost (the value will be forced to an empty object{})
}

console.log(sampleObject) // Object
// {
//    string: "string", number: 123, boolean: false,   null: null, notANumber: NaN, date: Date Thu Dec 31 2020 23:59:59, undefined: undefined, infinity: Infinity, regExp: /.*/
// }


console.log(typeof sampleObject.date) // object

const faultyClone = JSON.parse(JSON.stringify(sampleObject)) 
console.log(faultyClone) // Object
// { 
//    string: "string", number: 123, boolean: false, null: null, notANumber: null, date: Date Thu Dec 31 2021 04:59:59, infinity: null, regExp: {}
// }
// The date object has been stringified. the result of .toISOString()

console.log(typeof faultyCloen.date) // string

If you don't wanna use Dates, functions, RegExps, Maps, Sets, Blobs, undefined, Infinity, [NaN], sparse arrays, typed arrays or any other complex types within your object then there is a very simple one-liner to deep clone an object is: JSON.parse(JSON.stringify(object))


Need Help

Need help in raising fund to buy a Mechanical Keyboard. This pandemic has affected my family badly so can't ask my DAD for it. Please Help Me.

1.png


😎Thanks For Reading | Happy Coding⚑

Originally Here -> RAHULISM

Did you find this article valuable?

Support Rahul by becoming a sponsor. Any amount is appreciated!