深拷贝

1. 深拷贝与浅拷贝

浅复制,只是拷贝了基本类型的数据,而引用类型数据,复制后也是会发生引用,我们把这种拷贝叫做“浅拷贝(浅复制)”。

深复制和浅复制最根本的区别在于是否是真正获取了一个对象的复制实体,而不是引用。

  • 深复制在计算机中开辟了一块内存地址用于存放复制的对象。
  • 浅复制仅仅是指向被复制的内存地址,如果原地址中对象被改变了,那么浅复制出来的对象也会相应改变。

2. 浅拷贝

举个最常见的栗子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
var obj = {
"name": "username",
"data": [1,2,3]
}

function copy(tempObj1) {
var tempObj2 = {};
for (var i in tempObj1) {
tempObj2[i] = tempObj1[i];
}
return tempObj2;
}

var obj2 = copy(obj);

obj2obj 的一个副本,如果我们给 obj 添加一个值会怎样呢?

1
2
3
obj.data.push(4);
console.log(obj.data); // 1,2,3,4
console.log(obj2.data) // 1,2,3,4

通过打印,如果我们对 obj 中的对象属性(这里指数组 data)进行操作,那么浅拷贝出来的对象也会被改变。

3. 数组深拷贝

3.1 for 循环

1
2
3
4
5
6
7
8
9
10
11
12
13
14
var arr1 = [1,2,3,4,5]
var arr2 = copyArr(arr)
function copyArr(arr) {
let res = [];
for (let i = 0; i < arr.length; i++) {
res.push(arr[i])
}
return res;
}

arr1.push(6);

console.log('arr1:'+ arr1); // 1,2,3,4,5,6
console.log('arr2:'+ arr2); // 1,2,3,4,5

3.2 slice

1
2
3
4
5
6
7
var arr1 = ['George','John','Thomas','James','Adrew','Martin'];
var arr2 = arr1.slice(0);

arr1.push('Jane');

console.log('arr1:'+ arr1); // 'George','John','Thomas','James','Adrew','Martin','Jane'
console.log('arr2:'+ arr2); // 'George','John','Thomas','James','Adrew','Martin'

3.3 concat

1
2
3
4
5
6
7
var arr1 = [1,2,3,4,5];
var arr2 = arr1.concat();

arr1.push(6);

console.log('arr1:'+ arr1); // 1,2,3,4,5,6
console.log('arr2:'+ arr2); // 1,2,3,4,5

3.4 扩展运算符(ES6)

1
2
3
4
5
6
7
var arr1 = [1,2,3,4,5];
var arr2 = [...arr1];

arr1.push(6);

console.log('arr1:'+ arr1); // 1,2,3,4,5,6
console.log('arr2:'+ arr2); // 1,2,3,4,5

3.5 Array.from

1
2
3
4
5
6
7
var arr1 = [1,2,3,4,5];
var arr2 = Array.from(arr1);

arr1.push(6);

console.log('arr1:'+ arr1); // 1,2,3,4,5,6
console.log('arr2:'+ arr2); // 1,2,3,4,5

4. 对象深拷贝

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
var obj = {
"name": "username",
"age": 18,
"arr1": [1,2,3,4,5],
"arr2": [
{"name1" : "inner username"},
{"job" : "front-end engineer"}
],
"obj1": {
"ar": [1],
"ar2": [1]
}
};

obj.__proto__ = {
"proto_name": "proto_username",
"proto_age": 12,
}

4.1 递归方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
function copy(obj1, obj2){
var obj2 = obj2 || {};

for(var name in obj1){
if(typeof obj1[name] === "object"){
obj2[name]= (obj1[name].constructor === Array) ? [] : {};
copy(obj1[name],obj2[name]);
} else {
obj2[name] = obj1[name];
}
}

return obj2;
}

var obj2 = copy(obj,obj2);
obj.arr1.push(6);

console.log(obj.arr1); // 123456
console.log(obj2.arr1); // 12345

4.4 JSON.parse 方法

1
var obj2 = JSON.parse(JSON.stringify(obj));

缺点:

  • NaNInfinity 会被转换成 null
  • function 会被删掉
  • 无法拷贝循环引用