fenzhi-utils
Version:
分值前端项目的js函数库
103 lines (94 loc) • 2.63 kB
JavaScript
/**
* 深度克隆函数(包含函数、原型链、数组、循环引用,Symbol、Map、Set等)
* @param {*} obj
* @param {*} [hash=new WeakMap()]
* @return {*}
*/
/**
// 测试一:
let obj = {
str: 'hello world',
num: 123,
bool: true,
nul: null,
und: undefined,
arr: [1, 2, 3],
obj: { a: 1, b: 2, c: 3 },
func: function () {
console.log('hello world');
},
sym: Symbol('hello'),
map: new Map([
['name', 'Tom'],
['age', 18],
]),
set: new Set([1, 2, 3]),
};
obj.loop = obj; // 循环引用
let cloneObj = CustomDeepClone(obj);
console.log(cloneObj);
obj.str = 'AIGC';
console.log(cloneObj);
cloneObj.str = 'WEBAI';
console.log(cloneObj);
console.log(obj);
// 测试二:
let arr1 = [{ a: 6 }, { a: 7 }];
let arr2 = CustomDeepClone(arr1);
arr1[0].a = 8;
arr2[0].a = 9;
console.log(arr1);// [{ a: 8 }, { a: 7 }]
console.log(arr2);// [{ a: 9 }, { a: 7 }]
*/
export function CustomDeepClone(obj, hash = new WeakMap()) {
if (
Object(obj) !== obj ||
obj instanceof Function ||
obj instanceof RegExp ||
obj instanceof Error ||
obj instanceof Date
) {
return obj;
}
if (hash.has(obj)) {
return hash.get(obj);
}
let result;
try {
result = new obj.constructor();
} catch (e) {
result = Object.create(Object.getPrototypeOf(obj));
}
hash.set(obj, result);
if (obj instanceof Map) {
Array.from(obj, ([key, val]) =>
result.set(deepClone(key, hash), deepClone(val, hash))
);
} else if (obj instanceof Set) {
Array.from(obj, (key) => result.add(deepClone(key, hash)));
} else if (Array.isArray(obj)) {
result = obj.map((item) => deepClone(item, hash));
} else {
result = Object.getOwnPropertyNames(obj).reduce((acc, key) => {
const descriptor = Object.getOwnPropertyDescriptor(obj, key);
if (
descriptor.value !== undefined &&
typeof descriptor.value !== 'function'
) {
descriptor.value = deepClone(descriptor.value, hash);
} else if (descriptor.get || descriptor.set) {
descriptor.get = deepClone(descriptor.get, hash);
descriptor.set = deepClone(descriptor.set, hash);
}
Object.defineProperty(acc, key, descriptor);
return acc;
}, result);
Object.setPrototypeOf(result, deepClone(Object.getPrototypeOf(obj), hash));
}
if (obj instanceof Map) {
Object.setPrototypeOf(result, Map.prototype);
} else if (obj instanceof Set) {
Object.setPrototypeOf(result, Set.prototype);
}
return result;
}