深拷贝
1. 简易版深拷贝
js
/**
* 简易深拷贝实现
* @type {symbol}
*
* 缺点: 不能拷贝函数和Symbol值, 不能解决循环引用
*/
const s1 = Symbol()
const s2 = Symbol()
const obj = {
name: "hzy",
friend: {
name: 'kobe'
},
foo: function () {
console.log(this.name)
},
[s1]: 'abc',
s2: s2
}
// obj.inner = obj
// 上方这行代码会报错,循环引用报错
const info = JSON.parse((JSON.stringify(obj)))
console.log(info)
console.log(info === obj)
obj.friend.name = 'nice'
console.log(obj)
2. 完整版深拷贝
- 使用map来解决循环引用的问题
- 使用递归来解决对象的嵌套问题
- 判断数据类型为
Sybmol
,Set
,Map
,Function
的情况
js
const s1 = Symbol()
const s2 = Symbol()
function isObject(value) {
const valueType = typeof value;
return value !== null && (valueType === 'object' || valueType === 'function')
}
function deepClone(originValue, map = new WeakMap()) {
// 判断是否是一个Set类型
if(originValue instanceof Set) {
return new Set([...originValue])
}
// 判断是否是一个Map类型
if (originValue instanceof Map) {
return new Map([...originValue])
}
// 判断如果是Symbol的value, 那么创建一个新的Symbol
if (typeof originValue === 'symbol') {
return Symbol(originValue.description)
}
// 判断如果是函数类型, 那么直接使用同一个函数
if(typeof originValue === 'function') {
return originValue
}
// 判断传入originValue是否是一个对象类型
if(!isObject(originValue)) {
return originValue
}
if(map.has(originValue)) {
return map.get(originValue)
}
// 判断传入的对象是数组, 还是对象
const newObject = Array.isArray(originValue) ? [] : {}
map.set(originValue, newObject)
for(const key in originValue) {
newObject[key] = deepClone(originValue[key], map)
}
// 对Symbol的key进行特殊的处理
const symbolKeys = Object.getOwnPropertySymbols(originValue)
for(const sKeys of symbolKeys) {
newObject[sKeys] = deepClone(originValue[sKeys], map)
}
return newObject
}
// 测试代码
const obj = {
name: "hzy",
age: 18,
friend: {
name: "james",
address: {
city: "广州"
}
},
// 数组类型
hobbies: ["abc", "cba", "nba"],
// 函数类型
foo: function(m, n) {
console.log("foo function")
console.log("100代码逻辑")
return 123
},
// Symbol作为key和value
[s1]: "abc",
s2: s2,
// Set/Map
set: new Set(["aaa", "bbb", "ccc"]),
map: new Map([["aaa", "abc"], ["bbb", "cba"]])
}
const newObj = deepClone(obj)
console.log(newObj === obj)
obj.friend.name = 'kobe'
obj.friend.address.city = '成都'
console.log(newObj)