helpers/clone.js
2022-04-18 23:08:45 +02:00

53 lines
1.3 KiB
JavaScript

/**
* Clone object and all it's properties.
* Works recursively.
*
* @param {Object} obj Object to clone.
* @param {Mixed} seen For internal use only. Don't set.
* @return {Object} The clone.
*/
export const clone = (obj, seen) => {
if (typeof obj !== 'object' || obj === null) {
return obj;
}
seen = seen || new Map();
const lookup = seen.get(obj);
if (lookup) {
return lookup;
}
let newObj;
let cloneDeep = false;
if (!Array.isArray(obj)) {
if (obj instanceof Date) {
newObj = new Date(obj.getTime());
} else if (obj instanceof RegExp) {
newObj = new RegExp(obj);
} else {
const proto = Object.getPrototypeOf(obj);
if (proto && Object.isFrozen(obj)) {
newObj = obj;
} else {
newObj = Object.create(proto);
cloneDeep = true;
}
}
} else {
newObj = [];
cloneDeep = true;
}
seen.set(obj, newObj);
if (cloneDeep) {
const keys = Object.getOwnPropertyNames(obj);
for (let i = 0; i < keys.length; ++i) {
const key = keys[i];
const descriptor = Object.getOwnPropertyDescriptor(obj, key);
if (descriptor && (descriptor.get || descriptor.set)) {
Object.defineProperty(newObj, key, descriptor);
} else {
newObj[key] = clone(obj[key], seen);
}
}
}
return newObj;
};