Skip to content

Instantly share code, notes, and snippets.

@zhenghaohe
Last active October 8, 2022 20:05
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save zhenghaohe/4fbfb8cbe221618c947bcc782f2b637d to your computer and use it in GitHub Desktop.
Save zhenghaohe/4fbfb8cbe221618c947bcc782f2b637d to your computer and use it in GitHub Desktop.
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