【JS】 深拷贝

45 阅读1分钟

方法一:解构赋值

1. 演示

obj2 = {...obj1}

2. 存在问题

只能深拷贝一层,再深层次的对象不能被深拷贝,只能被浅拷贝

方法二:JSON 转换

1. 演示

obj2 = JSON.parse(JSON.stringify(obj1))

2. 存在问题

① bigint 类型的值无法转换,会报错

② undefined、symbol、function 等类型的值,会丢失

③ error regexp 等类型的值,会变为空对象

④ date 类型的值,会变为字符串,即使再次变为对象,属性值还是字符串

参考:深拷贝循环引用的处理

方法三:自定义深拷贝函数

<script>
    let p1 = {
        age: 38,
        son: {
            name: '小贝'
        },
        arr: [1, 2, 3, 4],
        // 以下不属于循环引用
        p1: {
            age: 38,
            son: {
                name: '小贝'
            },
            arr: [1, 2, 3, 4],
            p1: {
                age: 38,
                son: {
                    name: '小贝'
                },
                arr: [1, 2, 3, 4],
            }
        }
    }
    // p1.next = p1  // 循环引用

    p2 = deepClone(p1)
    // console.log(p2)

    function deepClone(targetObj, map = new WeakMap()) {

        // 首先判断是否是基本类型,若是,直接返回
        if (typeof targetObj !== 'object') {  // typeof 判断,'object' 包括了 array,object,null 三种
            return targetObj
        }

        // 判断是数组还是对象类型
        let cloneObj = Array.isArray(targetObj) ? [] : {}

        // 防止循环引用
        if (map.get(targetObj)) throw new Error('拷贝对象存在循环引用')
        map.set(targetObj, cloneObj)  // key 是源对象,value 是克隆对象
        // console.log(map)

        for (key in targetObj) {
            // 确保是自身的属性,而不是原型链上的属性
            if (targetObj.hasOwnProperty(key)) {
                // 递归克隆,直到返回的是基本类型
                cloneObj[key] = deepClone(targetObj[key], map)
            }
        }
        return cloneObj
    }
</script>