浅拷贝:
概念: 浅拷贝只会拷贝栈中的内容,而不会拷贝堆中的内容。也就是说当拷贝的对象是基本数据类型的话利用浅拷贝就可以完成拷贝,并且不会影响原来的内容;如果是引用数据类型的话,浅拷贝只会拷贝内容的第一层内容,而无法拷贝更深层的对象内容,也就是对于深层对象拷贝的是引用地址。
方法:
(1)Object.assign({}, target)
(2)扩展运算符 …target
(3)数组对象可以使用:arr.concat()、arr.slice()
图中可以看出浅拷贝修改第一层数据name不会影响原来的对象,但是修改深层对象friends则会影响原来的对象。
深拷贝:
概念: 深拷贝是通过在堆内存中重新开辟了一块内存空间来存放拷贝的对象,因此拷贝对象与被拷贝对象之间不会相互影响。
方法:
(1)JSON.parse(JSON.stringfy(target))
注意:这种方法不会拷贝 undefined;不会拷贝Symbol对象;不会拷贝函数;不能解决循环引用的问题,会报错。
(2)自定义深拷贝函数:
具体处理逻辑如下图。
代码如下:
function isObject(value) {
const valueType = typeof value
return (value !== null) && (valueType === "object" || valueType === "function")
}
function deepClone(originValue, map = new WeakMap()) { // map 保存循环引用
// 判断是否为Map类型
if (originValue instanceof Map) {
return new Map([...originValue])
}
// 判断是否为Set类型
if (originValue instanceof Set) {
return new Set([...originValue])
}
// 判断如果是Symbol的value 那么创建一个新的Symbol
if (typeof originValue === "symbol") {
return Symbol(originValue.description)
}
// 判断如果是函数那么直接使用同一个函数
if (typeof originValue === "function") {
return originValue
}
// 判断是否是对象 不是则直接返回原来的值
if (!isObject(originValue)) {
return originValue
}
// 判断是否存在Map对象
if (map.has(originValue)) {
return map.get(originValue)
}
const newObject = Array.isArray(originValue) ? [] : {} // 判断是否为数组
map.set(originValue, newObject) // 设置Map对象 解决循环引用的问题
for (key in originValue) {
newObject[key] = deepClone(originValue[key], map)
}
// 对Symbol的key进行特殊的处理
const symbolKeys = Object.getOwnPropertySymbols(originValue)
for (const sKey of symbolKeys) {
newObject[sKey] = deepClone(originValue[sKey], map)
}
return newObject
}
测试代码: