-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: Implement _.cloneDeep() function for deep cloning objects and a…
…rrays
- Loading branch information
1 parent
148ed0f
commit 68edb5d
Showing
1 changed file
with
78 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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) |