前言
我们在项目开发中经常会遇到复制一个对象进行相关业务开发的情况,要求新对象和原来的对象一模一样,而开发时对对象进行操作又不能影响原对象。那么怎么实现呢?本文就带你研究一下克隆对象的实现与原理。
浅克隆
概念是很枯燥的,我们用案例解释吧。
var jack = {
age: 25,
gender: "男"
}
//要求复制一个对象jackCopy,里面的属性和值与jack一模一样
有人会说那还不简单,你看
var jackCopy = jack;
console.log(jackCopy);
//输入的jsckCopy和jack一模一样
那你可以把jackCopy的age改变为20,再判断一下jack==jackCopy的值,然后输出一下jack试试
jackCopy.age = 20;
console.log(jack);
console.log(jack==jackCopy);
你会发现jack的age也变为20了,jack==jackCopy为true,为什么呢?首先jack是引用类型,不是原始数据类型,jack变量里存的是指向{age:25,gender:”男”}的地址值,jackCopy = jack 只是把地址值复制了一份给jackCpoy(按值传递),也就是说jackCopy和jack都通过相同的地址引用着{age:25,gender:”男”},他们俩是一个对象,这就不是克隆了。
浅克隆实现
var jack = {
age: 25,
gender: "男"
};
function clone(obj){
var newObj = {};
for(var key in obj){
newObj[key] = obj[key];
}
return newObj;
}
var jackCopy = clone(jack);
console.log(jackCopy);
console.log(jackCopy==jack);
输出jackCopy和jack一样,并且jackCopy==jack为false,实现了克隆。但上面的clone()函数实现克隆时,如果克隆的对象中的属性也是引用类型的话就不会再进一步克隆了。比如我们在jack中增加属性address
var jack = {
age:25,
gender:"男",
address:{
province:"河南",
city:"周口"
}
};
function clone(obj){
var newObj = {};
for(var key in obj){
newObj[key] = obj[key];
}
return newObj;
}
var jackCopy = clone(jack);
jackCopy.address.province = "上海";
console.log(jack.address);
console.log(jackCopy.address==jack.address);
我们发现修改jackCopy的address后jack的address也会跟着改变,又回到了原来的问题,jackCopy.address和jack.address同时引用着一个对象,因此我们并没有实现完全克隆,clone()函数只是实现了浅克隆,下面我们来实现深克隆。
深克隆
var jack = {
age:25,
gender:"男",
address:{
province:"河南",
city:"周口"
},
friend:["tom","rose","bob"]
};
function deepClone(obj){
//如果对象是null
if(obj===null){
return null;
}else if({}.toString.call(obj)==="[object Array]"){
//如果对象是数组
var newArr = [];
newArr = obj.slice();//全部截取obj数组到newArr中
return newArr;
}
var newObj = {};
for(var key in obj){
// 如果原对象的当前属性是原始值
if(typeof obj[key]!=="object"){
newObj[key] = obj[key]
}else{
// 如果当前属性还是引用类型就再次调用deepClone()函数
newObj[key] = deepClone(obj[key])
}
}
return newObj;
}
var jackCopy = deepClone(jack);
jackCopy.address.province = "上海";
console.log(jack);
console.log(jackCopy);
这就实现了深克隆,这个例子我们又给jack对象加了一个数组属性,因为数组复制时和对象不一样,不能用for in遍历,我们需要把数组和对象区分出来分别复制。
总结
- 如果一个对象中的属性都是原始类型的值,不再包含对象、数组等引用类型,我们可以用浅克隆进行复制。
- 如果一个对象包含内嵌的对象或者是数组的话,我们必须需要使用深克隆对它进行深层复制。
欢迎交流,个人博客