function deepClone(value, hash = new WeakMap()
) {
if (value === null || typeof value !== 'object') {
return value;
}
if (hash.has(value)) {
return hash.get(value);
}
if (value instanceof Date) {
return new Date(value);
}
if (value instanceof RegExp) {
return new RegExp(value.source, value.flags);
}
if (value instanceof Map) {
const cloneMap = new Map();
hash.set(value, cloneMap);
for (const [k, v] of value.entries()) {
cloneMap.set(deepClone(k, hash), deepClone(v, hash));
}
return cloneMap;
}
if (value instanceof Set) {
const cloneSet = new Set();
hash.set(value, cloneSet);
for (const item of value) {
cloneSet.add(deepClone(item, hash));
}
return cloneSet;
}
if (typeof value === 'function') {
return value;
}
if (Array.isArray(value)) {
const arrCopy = [];
hash.set(value, arrCopy);
for (let i = 0; i < value.length; i++) {
arrCopy[i] = deepClone(value[i], hash);
}
for (const sym of Object.getOwnPropertySymbols(value)) {
arrCopy[sym] = deepClone(value[sym], hash);
}
return arrCopy;
}
const proto = Object.getPrototypeOf(value);
const objCopy = Object.create(proto);
hash.set(value, objCopy);
const allProps = [
...Object.getOwnPropertyNames(value),
...Object.getOwnPropertySymbols(value)
];
for (const key of allProps) {
const descriptor = Object.getOwnPropertyDescriptor(value, key);
if (descriptor && typeof descriptor.value !== 'undefined') {
objCopy[key] = deepClone(descriptor.value, hash);
} else if (descriptor && (descriptor.get || descriptor.set)) {
Object.defineProperty(objCopy, key, descriptor);
}
}
return objCopy;
}