Open Hongbusi opened 2 years ago
基于洪佬的深拷贝自己又实现了一遍,增加了RegExp
、Date
、Map
、Set
的处理,平时没用过Buffer
类型的数据就不进行处理了,代码可能不够完善有点问题,欢迎大佬们指正。
function deepClone(originValue) {
/**
* 1.function、undefined、RegExp不会被解析
* 2.循环引用会抛出错误
* 如不考虑上述情况则可以使用此方法
*/
return JSON.parse(JSON.stringify(originValue));
}
/**
* 举个栗子:循环引用问题
* const obj = {};
* obj.obj = obj;
* deepClone(obj); // Uncaught TypeError: Converting circular structure to JSON
*/
/**
* @description:
* @param {*} originValue 源数据
* @param { WeakMap } map 便于处理循环引用问题
* @return {*} 深拷贝后的数据
*/
function deepClone(originValue, map = new WeakMap()) {
// 判断如果是 Symbol 的 value, 那么创建一个新的 Symbol
if (typeof originValue === "symbol") {
return Symbol(originValue.description);
}
// null、function、Date、简单数据类型则直接返回
if (originValue === null || originValue instanceof Date || typeof originValue !== "object") {
return originValue;
}
// 数据在weakMap中有引用则直接返回引用
if (map.has(originValue)) {
return map.get(originValue);
}
// 处理复杂数据类型Map、Set、Object、Array、RegExp
if (originValue instanceof RegExp) {
/**
* 正则需处理lastIndex, 举个🌰
* const reg = reg1 = /\d/g
* reg.exec('123')
* reg.lastIndex === reg1.lastIndex === 1 // true
*/
const newValue = new originValue.constructor(originValue.source, originValue.flags);
newValue.lastIndex = 0;
return newValue;
}
// 前提条件,原生数据类型或拥有正确的构造器
const bucket = new originValue.constructor();
map.set(originValue, bucket);
// 其余数据可以处理成可迭代类型, Reflect.ownKeys 相当于 Object.getOwnPropertyNames(target).concat(Object.getOwnPropertySymbols(target))
const iterator = originValue.constructor === Object ? Reflect.ownKeys(originValue) : originValue;
// 特殊情况: RegExp.prototype.exec 返回的数组, 比平时的数组多出input跟index属性
if(Array.isArray(originValue) && originValue[0] && Object.prototype.hasOwnProperty.call(originValue, 'index')) {
bucket.index = originValue.index
bucket.input = originValue.input
}
for (const item of iterator) {
let [key, value] = [];
if (Array.isArray(item)) {
[key, value] = item;
} else if (originValue.constructor === Object) {
[key, value] = [item, originValue[item]];
} else {
value = item;
}
setValue(bucket, key, deepClone(value, map));
}
return bucket;
}
function setValue(origin, key, value) {
switch (origin.constructor) {
case Map:
return origin.set(key, value);
case Set:
return origin.add(value);
case Array:
return origin.push(value);
default:
origin[key] = value;
break;
}
}
普通简单克隆 Source Code
export function deepClone(origin: unknown): unknown {
if (isArray(origin)) return origin.map(child => deepClone(child))
if (isObject(origin)) {
return Object.fromEntries(
Object.entries(origin).map(([k, v]) => [k, deepClone(v)]),
)
}
return origin
}
避免循环引用 Source Code
export function deepClone2(origin: any, hash = new WeakMap()): any {
if (isObject(origin)) {
if (hash.has(origin)) return hash.get(origin)
const target: any = isArray(origin) ? [] : {}
hash.set(origin, target)
Object.entries(origin).forEach(([k, v]: [string, any]) => {
if (isRegExp(v))
target[k] = new RegExp(v)
else if (isDate(v))
target[k] = new Date(v)
else
target[k] = deepClone2(v, hash)
})
return target
}
return origin
}