三者都是针对于引用类型!!引用类型包括:对象Object、数组Array,数据类型有:String、Number等。
赋值
当我们把一个对象赋值给一个新的变量时,赋的其实是该对象的在栈中的地址,而不是堆中的数据。也就是两个对象指向的是同一个存储空间,无论哪个对象发生改变,其实都是改变的同一个存储空间的内容,因此,两个对象是联动的,一起改变的。
浅拷贝
重新在堆中创建内存,拷贝前后对象的基本数据类型互不影响,但拷贝前后对象的引用类型因共享同一块内存,会相互影响。
深拷贝
从堆内存中开辟一个新的内存地址存放新对象,对对象中的子对象进行递归拷贝,拷贝前后的两个对象互不影响。
三者区别
口诀:赋值全都影响,浅拷贝只影响引用类型,深拷贝全不影响。
实例:
- 将
obj1
赋值给obj2
,当改变obj2
的基本数据类型(string)和引用类型(数组)时,obj1
对应的全都被修改。
//赋值
let obj1 = {
name : 'Mike',
arr : [1,[2,3],4],
};
let obj2 = obj1;
obj2.name = "Bob";
obj2.arr[1] =[5,6,7] ;
console.log('obj1',obj1) // obj1 { name: 'Bob', arr: [ 1, [ 5, 6, 7 ], 4 ] }
console.log('obj2',obj2) // obj2 { name: 'Bob', arr: [ 1, [ 5, 6, 7 ], 4 ] }
- 将
obj1
浅拷贝给obj2
,当改变obj2
的基本数据类型(string)和引用类型(数组)时,obj1
对应的引用类型(数组)被修改,基本数据类型(字符串)不变。
//浅拷贝
let obj1 = {
name : 'Mike',
arr : [1,[2,3],4],
};
let obj2 = shallowClone(obj1);
obj2.name = "Bob";
obj2.arr[1] =[5,6,7] ;
function shallowClone(source) {
var target = {};
for(var i in source) {
if (source.hasOwnProperty(i)) {
target[i] = source[i];
}
}
return target;
}
console.log('obj1',obj1) // obj1 { name: 'Mike', arr: [ 1, [ 5, 6, 7 ], 4 ] }
console.log('obj2',obj2) // obj2 { name: 'Bob', arr: [ 1, [ 5, 6, 7 ], 4 ] }
- 将
obj1
深拷贝给obj2
,当改变obj2
的基本数据类型(string)和引用类型(数组)时,obj1
对应的引用类型(数组)和基本数据类型(字符串)都不变。
//深拷贝
let obj1 = {
name : 'Mike',
arr : [1,[2,3],4],
};
let obj2 = deepClone(obj1);
obj2.name = "Bob";
obj2.arr[1] =[5,6,7] ;
function deepClone(obj) {
if (obj === null) return obj;
if (obj instanceof Date) return new Date(obj);
if (obj instanceof RegExp) return new RegExp(obj);
if (typeof obj !== "object") return obj;
let cloneObj = new obj.constructor();
for (let key in obj) {
if (obj.hasOwnProperty(key)) {
// 实现一个递归拷贝
cloneObj[key] = deepClone(obj[key]);
}
}
return cloneObj;
}
console.log('obj1',obj1) // obj1 { name: 'Mike', arr: [1,[2,3],4] }
console.log('obj2',obj2) // obj2 { name: 'Bob', arr: [ 1, [ 5, 6, 7 ], 4 ] }