js中深拷贝与浅拷贝

84 阅读2分钟

概念

浅拷贝: 如果里面有对象,则拷贝的是地址

深拷贝: 拷贝出一个完全互不影响的

浅拷贝实现方式

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)