很多面试都有手写深拷贝,道理都是懂
面试的时候就是写不上来,所以找时间自己手写了一遍
主要通过一个forEach函数遍历+递归的方式实现
首先判断是否引用类型,不是直接返回,若为引用类型进行递归赋值
因为用到递归,所以加入了weakMap优化
递归每次进入都判断一次类型 然后根据不同的进行创建不同的对象然后进行赋值
// 可遍历类型 Map Set Object Array
const typeArray = '[object Array]'
const typeObject = '[object Object]'
const typeMap = '[object Map]'
const typeSet = '[object Set]'
// 非原始类型的 不可遍历类型 Date RegExp Function
const typeDate = '[object Date]'
const typeRegExp = '[object RegExp]'
const typeFunction = '[object Function]'
// 非原始类型的 不可遍历类型的 集合(原始类型已经被过滤了不用再考虑了)
const simpleType = [typeDate, typeRegExp, typeFunction]
// 是否是引用类型
const isObject = (target) => {
if (target === null)
return false
else {
const type = typeof target
return type === 'object' || type === 'function'
}
};
// 获取标准类型
const getType = (target) => {
return Object.prototype.toString.call(target)
};
//克隆函数
const deepClone = (target, map = new WeakMap()) => {
//如果不是引用类型,直接返回
if (!isObject(target))
return target
//性能优化,如果放入过map中,直接在map中找到返回
if (map.get(target))
return map.get(target)
//获取类型并初始化返回对象
let targetType = getType(target)
let cloneTarget
//处理不可循环对象
if (simpleType.includes(targetType)) {
switch (targetType) {
//日期
case typeDate:
return new Date(target)
//正则
case typeRegExp:
const reg = /\w*$/
const result = new RegExp(target.source, reg.exec(target)[0])
// lastIndex 表示每次匹配时的开始位置
result.lastIndex = target.lastIndex
return result
//function
case typeFunction:
return target;
default:
return target;
}
}
// 区分处理
switch (targetType) {
//数组
case typeArray:
cloneTarget = []
map.set(target, cloneTarget)
target.forEach((element, index) => {
cloneTarget[index] = deepClone(element, map)
})
return cloneTarget
//对象
case typeObject:
cloneTarget = {}
map.set(target, cloneTarget);
[...Object.keys(target),...Object.getOwnPropertySymbols(target)].forEach((item) => {
cloneTarget[item] = deepClone(target[item], map)
})
return cloneTarget
//set集合
case typeSet:
cloneTarget = new Set()
map.set(target, cloneTarget)
target.forEach(element => {
cloneTarget.add(deepClone(element, map))
})
return cloneTarget
//Map
case typeMap:
cloneTarget = new Map()
map.set(target, cloneTarget)
target.forEach((val, key) => {
cloneTarget.set(key, deepClone(val, map))
})
return cloneTarget
default:
return target
}
}
//测试用例
let testObj = {
simple: {
Date: new Date(),
RegExp: /[\u4e00-\u9fa5]/gm,
function: () => {
console.log("我是一个function");
}
},
base: {
Number:111,
String: "hello world",
Boolean: true,
Null: null,
code: undefined
},
loop: {
arr: [1,2,3,4],
}
}
console.log(testObj)
console.log(deepClone(testObj))
测试结果: