直接上代碼:
/**
* JSON.parse(JSON.stringify(object))的問題在於
* 1、忽略undefined
* 2、忽略 Symbol
* 3、不能序列化函數
* 4、不能解決循環引用的物件
* DeepClone1 -> 解決類型的問題,包括陣列
* @param target
*/
export function DeepClone1(target) {
if (typeof target === 'object') {
// 考慮是否陣列
let cloneTarget = Array.isArray(target) ? [] : {};
for (const key in target) {
// 不考慮原型屬性
if (target.hasOwnProperty(key)) {
// 遞迴複製
cloneTarget[key] = DeepClone1(target[key]);
}
}
return cloneTarget;
// 非引用類型,直接返回即可
} else {
return target;
}
}
/**
* 解決循環引用的問題,用weakMap 替代 map, 內存釋放
* 用map額外開闢內存空間,存儲當前物件和複製物件的關係
*/
export function DeepClone2(target, map = new Map()) {
if (typeof target === 'object') {
let cloneTarget = Array.isArray(target) ? [] : {};
if (map.get(target)) {
return map.get(target);
}
map.set(target, cloneTarget);
for (const key in target) {
if (target.hasOwnProperty(key)) {
cloneTarget[key] = DeepClone2(target[key], map);
}
}
return cloneTarget;
} else {
return target;
}
}
// 引用類型除了物件和函數,還有null和function,可封裝一個isObject
function isObject(target) {
const type = typeof target;
return target !== null && (type === 'object' || type === 'function');
}
/**
* 按照是否可遍歷,將資料類型分類處理
* 可遍歷:object/array/map/set
* 不可遍歷:string/number/boolean/symbol、undefined/null、function、regex/date/error/math/JSON
* 返回 [object Array]
*/
function getType(target) {
return Object.prototype.toString.call(target);
}
// 函數類型,直接返回,一般不考慮