feat: implement deepClone function for deep cloning of objects and arrays
This commit is contained in:
93
lib/shared/helpers/deep-clone.ts
Normal file
93
lib/shared/helpers/deep-clone.ts
Normal file
@@ -0,0 +1,93 @@
|
||||
export function deepClone<T>(value: T): T {
|
||||
const seen = new WeakMap<any, any>()
|
||||
|
||||
const getRegExpFlags = (r: RegExp) => {
|
||||
let flags = ''
|
||||
if (r.global) flags += 'g'
|
||||
if (r.ignoreCase) flags += 'i'
|
||||
if (r.multiline) flags += 'm'
|
||||
if (r.dotAll) flags += 's'
|
||||
if (r.unicode) flags += 'u'
|
||||
if (r.sticky) flags += 'y'
|
||||
return flags
|
||||
}
|
||||
|
||||
function _clone(v: any): any {
|
||||
if (v === null || typeof v !== 'object') {
|
||||
return v
|
||||
}
|
||||
|
||||
if (seen.has(v)) {
|
||||
return seen.get(v)
|
||||
}
|
||||
|
||||
if (v instanceof Date) {
|
||||
return new Date(v.getTime())
|
||||
}
|
||||
|
||||
if (v instanceof RegExp) {
|
||||
return new RegExp(v.source, getRegExpFlags(v))
|
||||
}
|
||||
|
||||
if (v instanceof ArrayBuffer) {
|
||||
return v.slice(0)
|
||||
}
|
||||
|
||||
if (ArrayBuffer.isView(v)) {
|
||||
if (v instanceof DataView) {
|
||||
const buf = _clone(v.buffer)
|
||||
return new DataView(buf, v.byteOffset, v.byteLength)
|
||||
}
|
||||
|
||||
return new (v.constructor as any)(v)
|
||||
}
|
||||
|
||||
if (v instanceof Map) {
|
||||
const m = new Map()
|
||||
seen.set(v, m)
|
||||
for (const [k, val] of v.entries()) {
|
||||
m.set(_clone(k), _clone(val))
|
||||
}
|
||||
return m
|
||||
}
|
||||
|
||||
if (v instanceof Set) {
|
||||
const s = new Set()
|
||||
seen.set(v, s)
|
||||
for (const item of v.values()) s.add(_clone(item))
|
||||
return s
|
||||
}
|
||||
|
||||
if (Array.isArray(v)) {
|
||||
const arr: any[] = []
|
||||
seen.set(v, arr)
|
||||
for (let i = 0; i < v.length; i++) arr[i] = _clone(v[i])
|
||||
return arr as any
|
||||
}
|
||||
|
||||
if (typeof v === 'function') {
|
||||
return v
|
||||
}
|
||||
|
||||
const proto = Object.getPrototypeOf(v)
|
||||
const out = Object.create(proto)
|
||||
seen.set(v, out)
|
||||
|
||||
const descriptors = Object.getOwnPropertyDescriptors(v)
|
||||
for (const [key, desc] of Object.entries(descriptors)) {
|
||||
if ('value' in desc) desc.value = _clone(desc.value)
|
||||
Object.defineProperty(out, key, desc as PropertyDescriptor)
|
||||
}
|
||||
|
||||
const symbols = Object.getOwnPropertySymbols(v)
|
||||
for (const s of symbols) {
|
||||
const sd = Object.getOwnPropertyDescriptor(v, s)!
|
||||
if (sd && 'value' in sd) sd.value = _clone(sd.value)
|
||||
Object.defineProperty(out, s, sd as PropertyDescriptor)
|
||||
}
|
||||
|
||||
return out
|
||||
}
|
||||
|
||||
return _clone(value) as T
|
||||
}
|
||||
Reference in New Issue
Block a user