JavaScript的深拷贝和浅拷贝

1. JavaScript的变量类型

  • 基本类型:
     5种基本数据类型Undefined、Null、Boolean、NumberString,变量是直接按值存放的,存放在栈内存中的简单数据段,可以直接访问。

  • 引用类型:
    存放在堆内存中的对象,变量保存的是一个指针,这个指针指向另一个位置。当需要访问引用类型(如对象,数组等)的值时,首先从栈中获得该对象的地址指针,然后再从堆内存中取得所需的数据。

 JavaScript存储对象都是存地址的,所以浅拷贝会导致 obj1 和obj2 指向同一块内存地址。改变了其中一方的内容,都是在原来的内存上做修改会导致拷贝对象和源对象都发生改变,而深拷贝是开辟一块新的内存地址,将原对象的各个属性逐个复制进去。对拷贝对象和源对象各自的操作互不影响。

2. 深复制和浅复制

 深复制和浅复制只针对像 Object, Array 这样的复杂对象的。简单来说,浅复制是指只复制一层对象的属性,不会复制对象中的对象的属性,深复制则会递归复制了所有层级。

2.1 浅复制

方法一:

1
2
3
4
5
6
7
8
9
10
11
12
13
shallowCopy(obj) {
// typeof判断类型,数组和对象返回object
if (typeof obj !== "object") return;
// 根据obj的类型判断是新建一个数组还是对象
var newObj = obj instanceof Array ? [] : {};
// 遍历obj,并且判断是obj的属性才拷贝
for (var key in obj) {
if (obj.hasOwnProperty(key)) {
newObj[key] = obj[key];
}
}
return newObj;
}
1
2
3
4
5
6
var newUser = this.shallowCopy(user)
newUser.from = "shenzhen"
newUser.name.lastName = "HaHa"
console.log(newUser.from === user.from) //false
console.log(newUser.name.lastName === user.name.lastName) //true
//浅复制,只复制一层对象的属性,第二层对象的属性lastName/firstName不复制

方法二:

1
2
3
4
5
6
7
8
shallowCopy(obj) {
if (typeof obj !== "object") return;
//Object.assign() 方法可以把任意多个的源对象自身的可枚举属性拷贝给目标对象,然后返回目标对象。
if (obj instanceof Array) {
return Object.assign([], obj);
}
return Object.assign({}, obj);
}
1
2
3
4
5
6
7
8
9
10
11
var user = {
from: "zhuhai",
name: {
lastName: "Jessy"
}
}
var newUser = this.shallowCopy(user)
newUser.from = "shenzhen"
newUser.name.lastName = "HaHa"
console.log(newUser.from === user.from) //false
console.log(newUser.name.lastName === user.name.lastName) //true

2.2 深复制

方式一: 递归方式

1
2
3
4
5
6
7
8
9
10
11
deepCopy(obj) {
// 方式一 递归方式
if (typeof obj !== "object") return;
var newObj = obj instanceof Array ? [] : {};
for (var key in obj) {
if (obj.hasOwnProperty(key)) {
newObj[key] = typeof obj[key] === "object" ? this.deepCopy(obj[key]) : obj[key];
}
}
return newObj;
}
1
2
3
4
5
6
7
8
9
10
11
var user = {
from: "zhuhai",
name: {
lastName: "Jessy"
}
}
var newUser = this.deepCopy(user)
newUser.from = "shenzhen"
newUser.name.lastName = "HaHa"
console.log(newUser.from === user.from) //false
console.log(newUser.name.lastName === user.name.lastName) //false

方式二: JSON

1
2
3
4
5
6
7
8
deepCopy(obj) {
//方式二 JSON
if (typeof obj !== "object") {
return;
}
var str = JSON.stringify(obj);
return JSON.parse(str);
}
1
2
3
4
5
6
7
8
9
10
11
var user = {
from: "zhuhai",
name: {
lastName: "Jessy"
}
}
var newUser = this.deepCopy(user)
newUser.from = "shenzhen"
newUser.name.lastName = "HaHa"
console.log(newUser.from === user.from) //false
console.log(newUser.name.lastName === user.name.lastName) //false

作者: Jessy Hong