Last active
October 8, 2022 20:05
-
-
Save zhenghaohe/4fbfb8cbe221618c947bcc782f2b637d to your computer and use it in GitHub Desktop.
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
const isPrimitiveTypeOrFunction = (input) => | |
typeof input !== 'object' || typeof input === 'function' || input === null; | |
function getType(input) { | |
const lowerCaseTheFirstLetter = (str) => str[0].toLowerCase() + str.slice(1); | |
const type = typeof input; | |
if (type !== 'object') return type; | |
return lowerCaseTheFirstLetter( | |
Object.prototype.toString.call(input).replace(/^\[object (\S+)\]$/, '$1'), | |
); | |
} | |
export default function deepClone(input, cache = new Map()) { | |
// cache for detect cyclic references | |
if (isPrimitiveTypeOrFunction(input)) { | |
return input; | |
} | |
const type = getType(input); | |
if (type === 'set') { | |
const cloned = new Set(); | |
input.forEach((item) => { | |
cloned.add(deepClone(item)); | |
}); | |
return cloned; | |
} | |
if (type === 'map') { | |
const cloned = new Map(); | |
input.forEach((value, key) => { | |
cloned.set(key, deepClone(value)); | |
}); | |
return cloned; | |
} | |
if (type === 'function') { | |
return input; | |
} | |
if (type === 'array') { | |
return input.map((item) => deepClone(item)); | |
} | |
if (type === 'date') { | |
return new Date(input); | |
} | |
if (type === 'regExp') { | |
return new RegExp(input); | |
} | |
if (cache.has(input)) { | |
return cache.get(input); | |
} | |
// using an existing object as the prototype of the newly created object. | |
const cloned = Object.create(Object.getPrototypeOf(input)); | |
cache.set(input, cloned); | |
for (const key of Reflect.ownKeys(input)) { | |
cloned[key] = isPrimitiveTypeOrFunction(input[key]) | |
? input[key] | |
: deepClone(input[key], cache); | |
// preserve the original property descriptors | |
const propertyDescriptor = Object.getOwnPropertyDescriptor(input, key); | |
Object.defineProperty(cloned, key, { | |
writable: propertyDescriptor.writable, | |
enumerable: propertyDescriptor.enumerable, | |
configurable: propertyDescriptor.configurable, | |
}); | |
} | |
return cloned; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment