Add clone and reach helpers.
This commit is contained in:
52
clone.js
Normal file
52
clone.js
Normal file
@ -0,0 +1,52 @@
|
||||
/**
|
||||
* 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] = this._clone(obj[key], seen);
|
||||
}
|
||||
}
|
||||
}
|
||||
return newObj;
|
||||
};
|
Reference in New Issue
Block a user