浅谈js引用类型数据的浅拷贝和深拷贝
浅拷贝:你只能得到我的银行卡,但你却永远也得不到里面的钱!
js的数据存储类型
基础类型
直接指向存储
引用类型
指向存储地址的指针
引用类型的浅拷贝
var n={
a:1,
b:2,
c:3,
d:"123"
}
var m=n
直接将引用类型数据赋值给其他变量,只是将n浅拷贝给了m,当n或者m中的任意属性改变,另一者也会随之改变。
引用类型的伪深拷贝
枚举法
var n={
a:1,
b:2,
c:3,
d:"123"
}
var m={}
for(var i in n){
m[i]=n[i]
}
for in 只能遍历对象本身及原型链上可枚举的属性,所以并不能说是完全的拷贝,但是m和n的值是互不影响的。
JSON.stringify()和JSON.parse()
var m=JSON.parse(JSON.stringify(n));
- 使用
JSON.stringify()
将对象JSON化 - 在使用
JSON.parse()
将JSON格式转换为对象
这也可以实现伪深拷贝.
但这种方法也有个很大缺陷,就是会破坏原型链,并且无法拷贝属性值为function的属性,仅仅是单纯的复制。
Object.assign()
Object.assign()
方法可以实现无嵌套对象的深拷贝,我来解释一下是什么意思,就是说Object.assign()仅仅对对象的最顶层属性进行了深拷贝,而潜逃的数组或对象,并没有实现深拷贝,而是浅拷贝。
来举个栗子:
var n={
a:1,
b:2,
c:3,
d:"123",
e:{
a:1,
b:2,
c:{
a:3
}
}
}
var s;
// 进行伪深拷贝,
Object.assign(s,n);
s.a='test';
console.log(s)
console.log(n)
s.e.a="ABC"
console.log(s)
console.log(n)
可以看出,s最顶层的属性值发生改变时,不会影响n的最顶层属性值,但是嵌套对象内的属性会同时修改。
本人最常用的深拷贝
const clone = (obj) => {
var o
if (typeof obj === 'object') {
if (obj === null) {
o = null
} else {
if (obj instanceof Array) {
o = []
for (var i = 0, len = obj.length; i < len; i++) {
o.push(clone(obj[i]))
}
} else {
o = {}
for (var j in obj) {
o[j] = clone(obj[j])
}
}
}
} else { o = obj }
return o
}
这套拷贝基本可以实现深拷贝,当然如果对象结构不是很复杂,没有嵌套对象的话,还是建议使用Object.assign()
。