谈谈浅拷贝和深拷贝的区别,以及实现的方法
两者的区别:一个对象浅复制后,是深层次的对象地址的复制,并没有开辟新的栈,也就是复制的结果是两个对象指向同一个地址,修改其中一个对象的属性,则另一个对象的属性也会发生改变,而深复制的则是开辟了一个新的栈,两个对象对应两个不同的地址,修改一个对象的属性,不会改变另一个对象的属性。
话不多说,上代码:
// 原始对象
var obj = { a:1, arr: [2,3],say:function(){console.log('hello')},obj1:{arr:[34,55,5],hand:function(){console.log('hand')},obj3:{a:1,take:function(){console.log('take')}}}
};// 开始浅复制
var shallowObj = shallowCopy(obj);// 定义浅复制逻辑
function shallowCopy(src) {var dst = {};for (var prop in src) {if (src.hasOwnProperty(prop)) {dst[prop] = src[prop];}}return dst;
}// 改变复制后的新对象属性值(第一层属性)
shallowObj.a = 2;
shallowObj.arr = [9,8];
shallowObj.say = function(){console.log('world')
}// 打印新对象的及方法
console.dir(shallowObj)
shallowObj.say(); // world// 打印原对象及方法
console.dir(obj);
obj.say(); // hello
结果如图所示:
结论 : 修改新对象的属性值,第一层的属性值的确没有变化,重点来了,我们给第二层以及更深层次的属性复制试试
// 原始对象
var obj = { a:1, arr: [2,3],say:function(){console.log('hello')},obj1:{arr:[34,55,5],hand:function(){console.log('hand')},obj3:{a:1,take:function(){console.log('take')}}}
};// 开始浅复制
var shallowObj = shallowCopy(obj);// 定义浅复制逻辑
function shallowCopy(src) {var dst = {};for (var prop in src) {if (src.hasOwnProperty(prop)) {dst[prop] = src[prop];}}return dst;
}// 改变复制后的新对象的属性值(第二层以及更深层次)
shallowObj.obj1.obj3.take = function(){console.log('shallowObj_take')
}
shallowObj.obj1.hand = function(){console.log('shallowObj_hand')
}// 打印新对象的方法调用
shallowObj.obj1.obj3.take(); // shallowObj_take
shallowObj.obj1.hand(); // shallowObj_hand// 打印原对象的方法调用
obj.obj1.obj3.take(); // shallowObj_take
obj.obj1.hand(); // shallowObj_hand问题出现了:原对象的方法被新对象的修改,而产生变化。
原因是复制的是对象的地址指针,两个属性共同指向一个对象,只要其一发生变化,另一个也随之变化
深拷贝的方法:
1.可以递归递归去复制所有层级属性
// 原始对象
var obj = { a:1, arr: [2,3],say:function(){console.log('hello')},obj1:{arr:[34,55,5],hand:function(){console.log('hand')},obj3:{a:1,take:function(){console.log('take')}}}
};// 深复制逻辑(递归调用)
function deepClone(obj){let objClone = Array.isArray(obj)?[]:{};if(obj && typeof obj==="object"){for(key in obj){if(obj.hasOwnProperty(key)){//判断obj子元素是否为对象,如果是,递归复制if(obj[key] && typeof obj[key] ==="object"){objClone[key] = deepClone(obj[key]);}else{//如果不是,简单复制objClone[key] = obj[key];}}}}return objClone;
} // 开始深复制
var shallowObj = deepClone(obj);// 改变复制后的新对象的属性值(第二层以及更深层次)
shallowObj.obj1.obj3.take = function(){console.log('shallowObj_take')
}
shallowObj.obj1.hand = function(){console.log('shallowObj_hand')
}shallowObj.obj1.obj3.take(); // shallowObj_take
shallowObj.obj1.hand(); // shallowObj_handobj.obj1.obj3.take(); // take
obj.obj1.hand(); // hand结论:深拷贝后改变对象的属性值,不会影响原始对象的值。
2.除了递归,我们还可以借用JSON对象的parse和stringify
function deepClone(obj){let _obj = JSON.stringify(obj),objClone = JSON.parse(_obj);return objClone
}
let a=[0,1,[2,3],4],b=deepClone(a);
a[0]=1;
a[2][0]=1;
console.log(a,b);
3.除了上面两种方法之外,我们还可以借用JQ的extend方法
$.extend( [deep ], target, object1 [, objectN ] )
deep表示是否深拷贝,为true为深拷贝,为false,则为浅拷贝
target Object类型 目标对象,其他对象的成员属性将被附加到该对象上。
object1 objectN可选。 Object类型 第一个以及第N个被合并的对象。
let a=[0,1,[2,3],4],b=$.extend(true,[],a);
a[0]=1;
a[2][0]=1;
console.log(a,b);