什么是浅拷贝呢
我们首先创建一个新对象
let a = {
age: 20
};
let b = a;
b.age = 30;
console.log(a.age); // 30
当我们将创建一个新对象b拷贝a时,我们发现当改变b的属性age时 a的age属性也发生了改变,这就是浅拷贝。
什么是深拷贝呢
var name='张三'
var name2=name
name2='李四'
console.log(name) //张三
当我们改变name2时name却没有改变,这就是深拷贝。
那么同样是改变对象,为什么会产生差异呢?
是由于js的类型分为值类型
,引用类型
他们的存储方式不同。
值类型:string,boolean,null,number,undefined,symbol(ES6),BigInt(ES10)
引用数据类型:object,array,function。
JavaScript中的值类型
的变量存储结构如下表模拟所示,栈区中包括了变量的标识符以及变量所对应的值。
JavaScript中的引用类型
的变量也是存放在栈区的,不同的是,引用类型在栈区中存放的是变量名以及变量所对应值得引用地址,而变量所对应的值被存放在堆区中:
所以当我们创建一个新的对象(b)时,把原有的对象属性值(a),完整地拷贝过来。其中包括了原始类型的值,还有引用类型的内存地址。由于指向了同一个地址,所以改变a的值b的也会改变(a, b指向同一个内存地址(堆内存中存的值,改变的时候一起改变了)。
总结下来
浅拷贝(shallowCopy)只是增加了一个指针指向已存在的内存地址,
深拷贝(deepCopy)是增加了一个指针并且申请了一个新的内存,使这个增加的指针指向这个新的内存,
解决方法:
利用JSON类
就是将一个对象转为JSON字符串,在转回JSON对象
let a = {
age: 20
};
let b = JSON.parse(JSON.stringify(a));
b.age = 30;
console.log(a.age); // 20
使用Object.create()方法,创造一个新的内存地址
function deepClone(initalObj, finalObj) {
var obj = finalObj || {};
for (var i in initalObj) {
var prop = initalObj[i]; // 避免相互引用对象导致死循环,如initalObj.a = initalObj的情况
if(prop === obj) {
continue;
}
if (typeof prop === 'object') {
obj[i] = (prop.constructor === Array) ? [] : Object.create(prop);
} else {
obj[i] = prop;
}
}
return obj;
使用object.assign方法
let target=[];
let testArr=[2,3,5,8];
Object.assign(target,testArr);
console.log(target);
testArr.push(7);
递归
//判断要拷贝的对象类型(是否为引用类型)
function isComplexData (data) {
if(data===null||data===undefined){
return false
}
let flag = data.constructor===Array||data.constructor===Object
return flag
}
//递归拷贝函数
function deepCopy (data) {
if(!isComplexData (data)){
return data
}
let result = null
if(data.constructor===Array){
result = []
}else{
result = {}
}
for(let i in data){
result[i] = deepCopy (data[i])
}
return result
}
let a = {n:{x:0,y:1},m:2}
let b = deepCopy (a)
console.log(a,b)
a.n.x = 3
console.log(a,b)