深拷贝和浅拷贝

深拷贝

深拷贝是将一个对象从内存中完整的拷贝一份出来。从堆内存中开辟一个新的区域存放新的对象(新旧对象不共享同一块内存),且修改新对象不会影响到原来的对象。(深拷贝是在堆内存申请新的空间来存储数据,避免指针悬挂)

实现方式如下

复制代码
JSON.parse(JSON.stringify())

注意: 上面的方法虽然可以实现数组或对象的深拷贝,但是不能处理函数和正则,,经过上面的拷贝后得到的正则就不再是正则(变为空对象),得到的函数也不再是函数(变为null)。

递归方法实现深度克隆:遍历对象、数组直到里面是基本数据类型,然后再去复制,就是深度拷贝。

javascript 复制代码
function  deepClone(obj) {
        if (typeof obj !== 'object' || obj == null) {
            return obj
        }
        let result
        if (obj instanceof Array) {
            result = []
        } else {
            result = {}
        }
        for (let key in obj) {
            if (obj.hasOwnProperty(key)) {
                result[key] = deepClone(obj[key])
            }
        }
        return result
    }


    function deepClone(obj, hash = new WeakMap()) {
        if (obj === null) return obj; //如果是null或者是undefined 我就不进行拷贝操作
        if (obj instanceof Date) return new Date(obj);
        if (obj instanceof RegExp) return new RegExp(obj);  //如果可能是对象或者普通的值如果是函数的话就不需要拷贝
        if (typeof obj !== "object") return obj   //是对象的话就要深拷贝
        if (hash.get(obj)) return hash.get(obj);
        let cloneObj = new obj.constructor();
        //找到的是所属类型上的constructor,而原型上的constructor指向的是当前的类本身
        hash.set(obj, cloneObj);
        hash.set(obj, cloneObj)
        for (let key in obj) {
            if (obj.hasOwnProperty('key')) {
                cloneObj[key] = deepClone(obj[key], hash)
            }
        }
        return cloneObj
    }

浅拷贝

浅拷贝是创建一个新对象,这个对象有着原始对象的属性值的一份精确拷贝。如果属性是基本类型,拷贝的就是基本类型的值,如果属性是引用类型,拷贝的就是内存的地址。所以其中一个对象改变了地址,就会影响到另一个对象。

实现方式如下

1、Object.assign(); 可以把任意多个的源对象自身的可枚举属性拷贝给目标对象,最后返回目标对象。

javascript 复制代码
 let obj1 = {
        person: {
            name: '张三',
            age: 21
        },
        sports: 'basketball'
    }
    let obj2 = Object.assign({}, obj1)
    obj2.person.name = "艺青桑";
    obj2.sports = "football";
    console.log(obj1) // {person: {name: '艺青桑', age:21},sports: "basketball"}
    console.log(obj2); //    {person: {name: '艺青桑', age:21}, sports: 'football'}
复制代码

2、展开运算符 是es6的特性,它提供了一种非常方便的方式来进行浅拷贝,与object.assign()的功能相同

javascript 复制代码
let obj1 = { name: '文博', address: { x: 100, y: 100 } }
    let obj2 = { ...obj1 };
    obj1.address.x = 200;
    obj1.name = '嘉兴';
    console.log(obj2);//{ name: '文博', address: { x: 200, y: 100 }}
    console.log(obj1);//{ name: '嘉兴', address: { x: 200, y: 100 }}

3、Array.prototype.concat();

javascript 复制代码
 let arr=[1,3,{username:'贺丽'}]
    let arr2=arr.concat();
    arr[2].username='亚楠';
    console.log(arr)  //[1,3,{username:'亚楠'}]

4、 Array.prototype.slice()

javascript 复制代码
let arr = [1, 3, { username: '再兴' }]
    let arr3 = arr.slice();
    arr3[2].username = '艺青';
    console.log(arr) // [1,3,{username:'艺青'}]

赋值与深浅拷贝的区别

|-----|--------------------------------------------------------------------------------------------------------|--------------------------------------------------|---------------------------------------------------------|
| | 赋值 | 深拷贝 | 浅拷贝 |
| | 当我们把一个对象赋值给一个新的变量时,赋的其实是给该对象的在栈中的地址,而不是堆中的数据。也就是两个对象指向的是同一个存储空间,无论那个对象发生改变,其实都是改变的存储空间的内容,因此,两个对象是联动的。 | 从堆内存中开辟一个新的区域存放新对象,对对象中的子对象进行递归拷贝,拷贝前后的两个对象互不影响。 | 重新在堆中创建内存,拷贝前后对象的基本数据类型互不影响,但拷贝前后对象的引用类型因共享同一块内存,会相互影响。 |
| | 和原数据是否指向同一对象 | 第一层数据为基本数据类型且修改基本类型数据时 | 原数据中包含子对象且修改子对象时 |
| 赋值 | 是 | 改变会使原数据一起改变 | 改变会使原数据一起改变 |
| 深拷贝 | 否 | 改变不会使原数据一起改变 | 改变不会使原数据一起改变 |
| 浅拷贝 | 否 | 改变不会使原数据一起改变 | 改变会使原数据一起改变 |

文章中提到的栈内存和堆内存,有不懂得可以参观下面的地址

秒懂 栈内存和堆内存(深入底层)-CSDN博客

相关推荐
裴嘉靖2 分钟前
Vue 生成 PDF 完整教程
前端·vue.js·pdf
毕设小屋vx ylw2824264 分钟前
Java开发、Java Web应用、前端技术及Vue项目
java·前端·vue.js
冴羽1 小时前
今日苹果 App Store 前端源码泄露,赶紧 fork 一份看看
前端·javascript·typescript
蒜香拿铁1 小时前
Angular【router路由】
前端·javascript·angular.js
brzhang1 小时前
读懂 MiniMax Agent 的设计逻辑,然后我复刻了一个MiniMax Agent
前端·后端·架构
西洼工作室2 小时前
高效管理搜索历史:Vue持久化实践
前端·javascript·vue.js
广州华水科技2 小时前
北斗形变监测传感器在水库安全中的应用及技术优势分析
前端
樱花开了几轉2 小时前
element ui下拉框踩坑
开发语言·javascript·ui
开发者如是说2 小时前
Compose 开发桌面程序的一些问题
前端·架构
故事不长丨2 小时前
【Java SpringBoot+Vue 实现视频文件上传与存储】
java·javascript·spring boot·vscode·后端·vue·intellij-idea