/** 深拷贝实现
* 1. 基本功能实现,解决嵌套对象问题
* 2. 对数组类型的处理
* 3. 对函数类型的处理
* 4. 对 Symbol类型的处理(分别作为键值时的处理)
* 5. 对 Set 类型的处理
* 6. 对 Map 类型的处理
* 7. 解决循环引用问题
*/
// *判断是否为对象
function isObject(value) {
const valueType = typeof value
return value !== null && (valueType === 'object' || valueType == 'function')
}
function deepClone(originValue, map = new WeakMap()) {
//TODO 判断 originValue 是否为 Set 类型
if (originValue instanceof Set) {
return new Set([...originValue])
}
//TODO 判断 originValue 是否为 Map 类型
if (originValue instanceof Map) {
return new Map([...originValue])
}
//TODO 判断 originVlaue 是否为 symbol 类型
if (typeof originValue === 'symbol') {
return Symbol(originValue.description)
}
//TODO 判断 originValue 是否为函数类型
if (typeof originValue === 'function') {
return originValue
}
//TODO 判断 originValue 是否为对象类型
if (!isObject(originValue)) {
return originValue
}
// 2. 判断 newObj 是否已存在
if (map.has(originValue)) {
return map.get(originValue)
}
//TODO 判断 originValue 是否为数组类型
const newObj = Array.isArray(originValue) ? [] : {}
// 1. 将 newObj保存下来,用于下次运行时判断是否已经创建了 newObj
map.set(originValue, newObj)
for (const key in originValue) {
newObj[key] = deepClone(originValue[key], map)
}
//TODO 对 symbol类型的 key做特殊处理
const symbolKeys = Object.getOwnPropertySymbols(originValue)
for (const skey of symbolKeys) {
newObj[skey] = deepClone(originValue[skey], map)
}
return newObj
}
// 测试代码
let s1 = Symbol('aaa')
let s2 = Symbol('bbb')
const obj = {
name: 'CoderBin',
friend: {
name: 'Jack'
},
b: undefined,
s2: s2,
// 待优化
skill: ['js', 'vue', 'react'],
foo: () => { },
[s1]: 's11',
set: new Set(['a', 'b', 'c']),
map: new Map([
['a', 'aa'],
['b', 'bb']
])
}
obj.info = obj
const newObj = deepClone(obj)
console.log(newObj)