深拷贝和浅拷贝

数据类型存储

JavaScript中存在两大数据类型:

  • 基本类型
  • 引用类型

浅拷贝

浅拷贝,指的是创建新的数据,这个数据有着原始数据属性值的一份精确拷贝

如果属性是基本类型,拷贝的就是基本类型的值。如果属性是引用类型,拷贝的就是内存地址

即浅拷贝是拷贝一层,深层次的引用类型则共享内存地址

1
2
3
4
5
6
7
8
9
function shallowClone(obj) {
const newObj = {};
for(let prop in obj) {
if(obj.hasOwnProperty(prop)){
newObj[prop] = obj[prop];
}
}
return newObj;
}

JavaScript中,存在浅拷贝的现象有:

  • Object.assign
  • Array.prototype.slice(), Array.prototype.concat()
  • 使用拓展运算符(...)实现的复制

深拷贝

深拷贝开辟一个新的栈,两个对象属完成相同,但是对应两个不同的地址,修改一个对象的属性,不会改变另一个对象的属性

方法一:JSON.stringify()以及JSON.parse()

这种方法不可以拷贝 undefined functionRegExp 等类型

1
2
3
4
5
6
7
8
9
10
var obj5 = {
a: 1,
b: 2,
c: 3
}
var objString = JSON.stringify(obj5);
var obj6 = JSON.parse(objString);
obj5.a = 5;
console.log(obj5.a); // 5
console.log(obj6.a) //1

方法二:递归拷贝

可以拷贝function,但是不可以拷贝 undefined RegExp 等类型

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
34
35
36
37
38
39
40
41
42
43
const obj1 = {
age: 20,
name: '王明洁',
address: {
city: '杭州'
},
arr: ['a', 'b', 'c']
}

const obj2 = deepClone(obj1)
obj1.address.city = '上海'
console.log(obj2.address.city) //杭州

/**console.log(obj2.address.city)
* 深拷贝
* @param {Object} obj 要拷贝的对象
*/
function deepClone(obj={}){
/* 1.判断是基本类型还是引用类型 */
/* 如果不是对象和数组,或者为null,没有必要做深拷贝,直接返回 */
if(typeof obj !== 'object' || obj == null) {
return obj
}
/* 判断是数组还是对象 */
/* 初始化返回结果,如果obj是数组,则返回数组格式,如果obj是对象,则返回对象格式 */
let result
if(obj instanceof Array) {
result = []
} else {
result = {}
}

/* 递归 */
/* 返回结果 */
for(let key in obj) {
/* 判断一下key是不是obj自己拥有的属性,保证key不是原型的属性 */
if(obj.hasOwnProperty(key)) {
//递归调用
result[key] = deepClone(obj[key])
}
}
return result
}

小结

前提为拷贝类型为引用类型的情况下:

  • 浅拷贝是拷贝一层,属性为对象时,浅拷贝是复制,两个对象指向同一个地址
  • 深拷贝是递归拷贝深层次,属性为对象时,深拷贝是新开栈,两个对象指向不同的地址