手写深拷贝
# 手写深拷贝
# 深拷贝
深拷贝是将一个对象从内存中完整的拷贝一份出来,从堆内存中开辟一个新的区域存放新对象(新旧对象不共享同一块内存),且修改新对象不会影响原对象(深拷贝采用了在堆内存中申请新的空间来存储数据,这样每个可以避免指针悬挂)
# 浅拷贝
如果属性是基本类型,拷贝的就是基本类型的值,如果属性是引用类型,拷贝的就是内存地址(新旧对象共享同一块内存),所以如果其中一个对象改变了这个地址,就会影响到另一个对象(只是拷贝了指针,使得两个指针指向同一个地址,这样在对象块结束,调用函数析构的时,会造成同一份资源析构2次,即delete同一块内存2次,造成程序崩溃);
# 深拷贝与浅拷贝的区别
- 当我们把一个对象赋值给一个新的变量时,赋的其实是该对象的在栈中的地址,而不是堆中的数据。也就是两个对象指向的是同一个存储空间,无论哪个对象发生改变,其实都是改变的存储空间的内容,因此,两个对象是联动的
- 浅拷贝是按位拷贝对象,它会创建一个新对象,这个对象有着原始对象属性值的一份精确拷贝。如果属性是基本类型,拷贝的就是基本类型的值;如果属性是内存地址(引用类型),拷贝的就是内存地址 ,因此如果其中一个对象改变了这个地址,就会影响到另一个对象。即默认拷贝构造函数只是对对象进行浅拷贝复制(逐个成员依次拷贝),即只复制对象空间而不复制资源
# 深拷贝实现
先定义一个object对象
const obj1 = {
name:"张三",
age: 18,
address: {
city: "重庆"
},
hobby: ["编程", "篮球"],
fn: function() {
console.log(123);
}
}
const obj2 = obj1; // 此时进行的是浅拷贝,只拷贝obj1在栈中的内存地址
console.log(obj2)
1
2
3
4
5
6
7
8
9
10
11
12
13
2
3
4
5
6
7
8
9
10
11
12
13
# 使用JSON.parse和JSON.stringify
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));
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
修改基本数据类型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()方法
// 记得引入js的库
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
2
3
4
5
6
7
8
9
10
11
12
13
# 递归实现
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);
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
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
此方法没考虑循环引用问题
# 循环引用问题
# lodash工具包
https://www.lodashjs.com/
直接使用lodash提供给我们的函数_.cloneDeep
# 参考文章
https://juejin.cn/post/7134970746580762637
https://juejin.cn/post/7142434398225301534
编辑 (opens new window)
上次更新: 2024/12/19, 09:15:30