手写深拷贝
深拷贝
深拷贝是将一个对象从内存中完整的拷贝一份出来,从堆内存中开辟一个新的区域存放新对象(新旧对象不共享同一块内存),且修改新对象不会影响原对象(深拷贝采用了在堆内存中申请新的空间来存储数据,这样每个可以避免指针悬挂)
浅拷贝
如果属性是基本类型,拷贝的就是基本类型的值,如果属性是引用类型,拷贝的就是内存地址(新旧对象共享同一块内存),所以如果其中一个对象改变了这个地址,就会影响到另一个对象(只是拷贝了指针,使得两个指针指向同一个地址,这样在对象块结束,调用函数析构的时,会造成同一份资源析构2次,即delete同一块内存2次,造成程序崩溃);
深拷贝与浅拷贝的区别
- 当我们把一个对象赋值给一个新的变量时,赋的其实是该对象的在栈中的地址,而不是堆中的数据。也就是两个对象指向的是同一个存储空间,无论哪个对象发生改变,其实都是改变的存储空间的内容,因此,两个对象是联动的
- 浅拷贝是按位拷贝对象,它会创建一个新对象,这个对象有着原始对象属性值的一份精确拷贝。如果属性是基本类型,拷贝的就是基本类型的值;如果属性是内存地址(引用类型),拷贝的就是内存地址 ,因此如果其中一个对象改变了这个地址,就会影响到另一个对象。即默认拷贝构造函数只是对对象进行浅拷贝复制(逐个成员依次拷贝),即只复制对象空间而不复制资源

深拷贝实现
先定义一个object对象
1 2 3 4 5 6 7 8 9 10 11 12 13
| const obj1 = { name:"张三", age: 18, address: { city: "重庆" }, hobby: ["编程", "篮球"], fn: function() { console.log(123); } } const obj2 = obj1; console.log(obj2)
|

使用JSON.parse和JSON.stringify
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| const obj1 = { name:"张三", age: 18, address: { city: "重庆" }, hobby: ["编程", "篮球"], fn: function() { console.log(123); } } const obj2 = deepClone(obj1); function deepClone(obj) { return JSON.parse(JSON.stringify(obj)); }
|
修改基本数据类型name的值,可以看到只有obj2发生变化

修改引用类型 address集合,hobby数组的值,也是只有obj2发生变化


但是函数却没有拷贝过来

JSON.parse()
方法用来解析 JSON 字符串,构造由字符串描述的 JavaScript 值或对象 因此undefined不能被转换并抛出异常:”undefined”不是有效的 JSON;
参考文章:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify

jQuery.extend()方法
1 2 3 4 5 6 7 8 9 10 11 12 13
| const obj1 = { name:"张三", age: 18, address: { city: "重庆" }, hobby: ["编程", "篮球"], fn: function() { console.log(123); } } const obj2 = $.extend(true,{},obj1);
|

递归实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
| const obj1 = { name:"张三", age: 18, address: { city: "重庆", phone: { number: 111111, a: { b: 3, e: [1,2,3] } } }, hobby: ["编程", "篮球", {a: {b: {d:111}}}], fn: function() { console.log(123); } } function deepClone(obj) { if (typeof obj != "object" || obj == null) { return obj; } let res = obj instanceof Array ? [] : {}; for(let key in obj) { if (obj.hasOwnProperty(key)) { res[key] = deepClone(obj[key]); } } return res; }
const obj2 = deepClone(obj1);
|
此方法没考虑循环引用问题

循环引用问题
lodash工具包
https://www.lodashjs.com/
直接使用lodash提供给我们的函数_.cloneDeep
参考文章
https://juejin.cn/post/7134970746580762637
https://juejin.cn/post/7142434398225301534