1.概念:
浅拷贝(引用拷贝):指的是拷贝一层,对于更深层的只拷贝其引用地址
深拷贝(值拷贝):拷贝多层,即在深拷贝一个对象的过程中,不仅复制了该对象的值,而且重新开辟了新的内存空间,将新对象存入新开辟的内存空间,此后新对象与原来的对象互不影响。
2.基本认识
接图:
如图:var声名了一个obj对象在栈中存储,其中的obj.msg.name在栈中存储的是它的地址,而它的值则另外在堆中存储,并且这个地址指向这个内存空间。 现在我将obj遍历到o中,则o会在栈中开辟一个空间,将name和id的值存入该空间,而o.msg.name则在栈中存储的是地址,并且该地址也指向和obj.msg.name同一个堆空间(此过程为浅拷贝)。如下代码:
<script>
// 浅拷贝只是拷贝一层, 更深层次对象级别的只拷贝引用.( 把更深层次的对象的地址拷贝)
// 深拷贝拷贝多层, 每一级别的数据都会拷贝.
var obj = {
id: 1,
name: 'andy',
msg: {
age: 18
}
};
var o = {};
// for (var k in obj) {
// // k 是属性名 obj[k] 是属性值
// o[k] = obj[k];
// }
// console.log(o);
// o.msg.age = 20;
// console.log(obj); // 浅拷贝把更深层次的对象的地址拷贝给了它,此时o中msg.age的值变化会同时影响到obj中的msg.age
</script>
如图:先声明了obj对象,并对其进行深拷贝给o。此时我们会注意到o在栈中新开辟了一个空间用来存储本身,而对于o中msg.sex和msg.age则在堆中开辟了不同于obj的堆存储空间。此时堆中的两个存储空间互不干扰。代码如下:
<script>
// 深拷贝拷贝多层, 每一级别的数据都会拷贝.
var obj = {
id: 1,
name: 'andy',
msg: {
age: 18
},
color: ['pink', 'red']
};
var o = {};
// 封装函数
function deepCopy(newobj, oldobj) {
for (var k in oldobj) {
// 判断我们的属性值属于那种数据类型
// 1. 获取属性值 oldobj[k]
var item = oldobj[k];
// 2. 判断这个值是否是数组
if (item instanceof Array) {
newobj[k] = []
deepCopy(newobj[k], item);
// 3. 判断这个值是否是对象
} else if(item instanceof Object) {
newobj[k] = {};
deepCopy(newobj[k], item);
// 4. 属于简单数据类型
} else {
newobj[k] = item;
}
}
}
deepCopy(o, obj); // 这一步进行了深拷贝
console.log(o);
o.id = 'obj没有修改';
o.msg.age = 100; // 无效修改
console.log(obj); // obj.msg.age 还是 18
</script>
3.实际应用:
深拷贝:
1.对于基本数据类型来说,在赋值操作中是值拷贝(深拷贝),如var num = 10, var num1 = num,将num的值赋值给num1,此过程为深拷贝。
2.对于Object,Array而言,直接进行赋值操作是得不到深拷贝的,因此,有如下方法可深拷贝成功:
1.Array.from方法
Array.from()是数组内置的一个方法,可以实现深拷贝。
<script>
var arr1 = ['zs', 'ls', 'ww'];
var arr2 = Array.from(arr1);
console.log(arr1); // ['zs', 'ls', 'ww']
arr2[0] = '李白' // 改变arr2[0]的值,但arr1[0]仍然为'zs'
console.log(arr1); // ['zs', 'ls', 'ww']
</script>
2.slice方法
<script>
var arr1 = ['zs', 'ls', 'ww'];
var arr2 = arr1.slice();
arr2[0] = '李白';
console.log(arr1); // ['zs', 'ls', 'ww']
console.log(arr2); // ['李白', 'ls', 'ww']
</script>
浅拷贝:
1.Object.assign()
<script>
var obj = {
id: 1,
name: 'andy',
msg: {
age: 18
}
};
var o = {};
// 浅拷贝新方法 (推荐)
Object.assign(o, obj); // 把后者拷贝到前者
console.log(o);
o.msg.age = 20;
o.id = 'dadadadadf' // 浅拷贝不能把主对象的属性值修改掉
console.log(obj); // 浅拷贝把更深层次的对象的地址拷贝给了它
</script>