浅拷贝
复杂类型即对象在赋值过程中其实复制的是一个地址(指针),这个指针指向计算机的一小块内存,从而导致修改一个地方其他地方也跟着改变,但我们不希望这种情况发生,可以使用浅拷贝解决这个问题1
2
3
4
5
6let a = {
age: 18
}
let b = a;
a.age = 20;
console.log(b.age); // 输出20
通过Object.assign,它只会拷贝所有的属性值到新对象中,如果属性值是对象的话,拷贝的是地址,并不是深拷贝
1
2
3
4
5
6let a = {
age: 18
}
let b = Object.assign({},a);
a.age = 20;
console.log(b.age); // 18另外还可以通过展开运算符…来实现浅拷贝
1
2
3
4
5
6let a = {
age: 18
}
let b = { ...a }
a.age = 20
console.log(b.age) // 18
浅拷贝只解决了第一层问题,如果接下去的值中还有对象的话,那么就又回到最开始的话题了,两者享有同一个地址。要解决这个问题,我们就要使用深拷贝了
深拷贝
- JSON实现深拷贝
1
2
3
4
5
6
7
8
9let a = {
age: 18,
jobs: {
first: 'doctor'
}
}
let b = JSON.parse(JSON.stringify(a)) // 将这个对象变成字符串,再从这个字符串中生成一个对象
a.jobs.first = 'teacher'
console.log(b.jobs.first) // doctor
但是这个方法有局限性,JSON不支持函数,引用,undefined,正则,Date日期对象
- 如果想自己实现一个深拷贝,这里只能实现一个简易版本,有许多边界情况没有考虑到,但在实际应用中更推荐lodash的深拷贝函数https://lodash.com/docs/4.17.11#cloneDeep
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
28function deepClone(obj) {
function isObject(o) {
return (typeof o === 'object' || typeof o === 'function') && o !== null
}
if (!isObject(obj)) {
throw new Error('非对象')
}
let isArray = Array.isArray(obj)
let newObj = isArray ? [...obj] : { ...obj }
Reflect.ownKeys(newObj).forEach(key => {
newObj[key] = isObject(obj[key]) ? deepClone(obj[key]) : obj[key]
})
return newObj
}
let obj = {
a: [1, 2, 3],
b: {
c: 2,
d: 3
}
}
let newObj = deepClone(obj)
newObj.b.c = 1
console.log(obj.b.c) // 2