Skip to content

Commit

Permalink
feat: Implement _.cloneDeep() function for deep cloning objects and a…
Browse files Browse the repository at this point in the history
…rrays
  • Loading branch information
Shaban-Eissa committed Jun 7, 2024
1 parent 148ed0f commit 68edb5d
Showing 1 changed file with 78 additions and 0 deletions.
78 changes: 78 additions & 0 deletions 63.create-cloneDeep.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
# 63. create `_.cloneDeep()`
cloneDeep is a function provided by the Lodash library in JavaScript, which allows for deep cloning of objects and arrays. This means it creates a complete copy of a given value, including nested objects or arrays, ensuring that any changes to the cloned value do not affect the original.

### Problem

https://bigfrontend.dev/problem/create-cloneDeep

#

### Problem Description

`Object.assign()` could be used to do shallow copy, while for recursive deep copy, [\_.cloneDeep](https://lodash.com/docs/4.17.15#cloneDeep) could be very useful.

Can you create your own `_.cloneDeep()`?

The lodash implementation actually covers a lot of data types, for simplicity, your code just need to cover

1. [primitive types](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures#Primitive_values) and their wrapper Object
2. Plain Objects (Object literal) with all enumerable properties
3. Array

#

### Understanding the problem

Write a function that creates a deep clone of a value. The function should handle primitive types, Object literal and Array.

#

### Approach

First, check the data type of the source data, return the source if it is a primitive or `null`. Depending the data type of the source, either create an empty array or an empty object to store the cloned value. Get all enumerable properties of the source including all symbol properties. Loop over the properties. For each property, recursively call the function with property value as argument; create the property in the cloned object/array and set its value to the result of the recursive call.

🙋‍♀️🙋‍♂️ In the initial attempt, I didn't handle the circular reference. We can use a `WeakMap` to store the source and its copy. If the source object is already in the `WeakMap`, return its corresponding copy instead of recursing further.

### Solution

```js
// Use WeakMap that stores cloned results to handle circular reference.
const cachedResult = new WeakMap();

function cloneDeep(data) {
if (data === null || data === undefined) {
return data;
}

if (typeof data !== 'object') {
return data;
}

// If the source object is already in the WeakMap,
// its corresponding copy is returned instead of recursing
// further.
if (cachedResult.has(data)) {
return cachedResult.get(data);
}

const clone = Array.isArray(data) ? [] : {};
// Store the source object and its clone in the WeakMap.
cachedResult.set(data, clone);

const keys = [
...Object.getOwnPropertyNames(data),
...Object.getOwnPropertySymbols(data),
];
for (const key of keys) {
clone[key] = cloneDeep(data[key]);
}

return clone;
}
```

#

### Reference

[Javascript Deep Clone Object with Circular References](https://stackoverflow.com/questions/40291987/javascript-deep-clone-object-with-circular-references)

0 comments on commit 68edb5d

Please sign in to comment.