对象的深拷贝

刚开始学 JS 的时候,发现一个有趣的现象。

1
2
3
4
5
6
7
8
9
10
11
12
var a = [1, 2, 3, 4, 5];
var b = a;
b[1] = 0;
a; //[1,0,3,4,5]

var obj1 = {
name: "张三",
age: 18,
};
var obj2 = obj1;
obj2.name = "李四";
obj1.name; //张三

当时就觉得很奇怪啊,我又没有修改原数组和原对象,怎么就改变了呢?
后来才知道,如果直接把一个对象(数组)赋值给一个变量,那这个变量实际上是这个赋值对象的引用。什么意思呢,就是说这个变量指向的是原来的这个对象,那修改这个变量实际就是修改原来的这个变量。那我们应该怎么避免这个问题呢?这就是对象的(深)拷贝,话不多说,直接看代码。
拷贝一个对象(数组)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
var copyObj = function (obj) {
var o = {};
for (var i in obj) {
o[i] = obj[i];
}
return o;
};
var a = {
name: "张三",
age: "18",
skills: {
swim: "prro",
run: "poor",
eat: "good",
},
};
var b = copyObj(a);
b.name = "李四"; //李四
a.name; //张三

乍一看,b 对象就是复制的 a 对象,而且实现我们想要的效果,其实不然,我们继续

1
2
b.skills.run = "fast"; //fast
a.skills.run; //fast

傻了吧,怎么 a 的 skills.run 又被改变了,原因是如果对象的属性是一个对象(数组),那么上面的拷贝方法其实是没有拷贝这个属性的,只是一个内存地址的指向。这就是对象的浅拷贝,那我们怎么才能深拷贝一个对象呢?只要递归调用”浅拷贝”就行了。

1
2
3
4
5
6
7
8
9
10
11
12
var copyObj = function (obj, o) {
var o = o || {};
for (var i in obj) {
if (typeof obj[i] == "object") {
o[i] = obj[i].constructor === Array ? [] : {};
copyObj(obj[i], o[i]);
} else {
o[i] = obj[i];
}
}
return o;
};

再试试,是不是就对了!

[越努力,越幸运!]