概念
浅拷贝: 如果里面有对象,则拷贝的是地址
深拷贝: 拷贝出一个完全互不影响的
浅拷贝实现方式
1、解析赋值
let arr1 = [1,2,3]
let arr2 = ...arr1
console.log(arr2)
2.Object.assign
let arr1 = [1,2,3]
console.log(Object.assign(arr1))
深拷贝实现方式
1、JSON.parse(JSON.stringify(obj))
原理:就是利用JSON.stringify将js对象序列化(JSON字符串),再使用JSON.parse来反序列化(还原)js对象。 缺点: (1)拷贝的对象中如果有函数(值),undefined(值),symbol(键或值为symbol类型),当使用过JSON.stringify()进行处理之后,都会消失。 (2)如果存在对象循环引用,也会报错
2、使用loadsh库里面的cloneDeep函数
缺点:需要另外引用包,不是原生的函数 缺点是需要注意处理 tree-shaking 否则会有性能损耗
3、使用structuredClone方法
优点:浏览器原生函数 缺点: (1)不能处理value为函数、symbol类型的值,会直接报错 (2)不能拷贝键值为symbol的属性,忽略该属性 (3)循环引用,undefined值都可以拷贝来
4、自己实现的深拷贝(参考codewhy老师的方法)
面试的时候关键是递归拷贝,处理循环引用的问题
function isObject (objTemp){
let type = typeof objTemp
return objTemp !== null && (type === "function" || type === "object")
}
function deepClone(oldObj, map = new WeakMap()){
// 判断是否是set
if(oldObj instanceof Set){
return new Set([...oldObj])
}
// 判断是否为map
if(oldObj instanceof Map){
return new Map([...oldObj])
}
// 判断是否为函数
if(typeof oldObj === "function") return oldObj
// 判断如果是symbol类型值
if(typeof oldObj === "symbol") return Symbol(oldObj.description)
// 解决嵌套赋值问题
if(!isObject(oldObj)) return oldObj
// 解决循环引用的问题
if(map.has(oldObj)) return map.get(oldObj)
// 解决值为数组问题
let newObj = Array.isArray(oldObj)?[]:{}
map.set(oldObj, newObj)
for (const newObjKey in oldObj) {
newObj[newObjKey] = deepClone(oldObj[newObjKey], map)
}
// 解决symbol无法遍历问题
let symbolArr = Object.getOwnPropertySymbols(oldObj)
for (const symbol of symbolArr) {
// const newSkey = symbol.description
newObj[symbol] = deepClone(oldObj[symbol], map)
}
return newObj
}
let symbol1 = Symbol("aaa")
let symbol2 = Symbol("bbb")
let obj = {
"a":1,
[symbol1]:"111",
"d":symbol2,
"b":{
"c":1
},
"arr":[1,2,3,4],
"set":new Set([1,2,3]),
"map":new Map([[1,2],[2,3]]),
"function":function (a){
return a
}
}
obj.objTemp = obj
let copyObj = deepClone(obj)
console.log(copyObj)