JS对象的浅克隆和深克隆,是我们可能会常用到的方法。对象克隆是指
我们有一个对象A:
A={
name:"jack",
hobby:['play','sleep'],
son:{
name:"jerry",
hobby:['study','excercise']
}
}
现在新建一个对象 var B={ },我们想把A对象的内容完完全全地拷贝到B当中去,用到的方法即为对象的克隆。
在学习具体的实现方法之前,先要弄明白JS中的对象。在JS中,一切皆为对象,对象又可以分为两类,一类是不可改变的原始值(string number boolean undefined null)他们存储在"栈"中;另一类是引用值(array object function )他们存储在"堆"中。
在JS中,我们还要搞清楚值的传递: 传递原始值则仅仅传的是一个值,而传传递引用值传的是地址。eg :
1 var a = 1;
2 var b = a;
3 a = 2;
4 console.log(b); // 1
5
6 var a = 'hello';
7 var b = a;
8 a = 'world';
9 console.log(b); // hello
10
11 var a = true;
12 var b = a;
13 a = false;
14 console.log(b); // true
通过以上代码不难发现,如果要克隆原始值,直接复制即可,且改变原始值的不会影响拷贝过来的数据。
再来看引用值的克隆:
var a = [1, 2, 3];
var b = a;
a.push(4);
console.log(b); // [1, 2, 3, 4]
这个时候,我们就发现,改变原数组,新的数组也会跟着变。那怎么才能不让他跟着变呢?
浅克隆
回到开头的对象A,
我们现在通过浅克隆的方式把A克隆到B
var B={
name:A.name,
hobby:B.hobby,
son:B.son
}
封装为方法:
function clone(origin,target){
for(var prop in origin){
target[prop]=origin[prop];
}
return target;
}
这就叫作浅克隆,但问题就是,原始值克隆过去是OK的,但引用值就麻烦了,改了一个,另一个就跟着变。
深克隆
既然要深克隆,我们就得通过嵌套遍历的方式,一个一个检查:
B[0]:“你是原始值吗?”
A[0] : “是”
B[0]:“直接复制过来!”
—————————————
B[1]:“你是原始值吗?”
A[1] :“不,我是引用值”
“新建一个空对象(数组)!再继续往下追问”
—————————————
B[1][0]:“你是原始值吗?”
A[1][0] : “是”
B[1][0]:“直接复制过来!”
. . . . . .
所以,在对象的深克隆方法中,显而易见的,我们要用到循环嵌套和递归的方法,具体分为以下5个步骤:
1、遍历对象
2、判断是不是原始值 for(var prop in obj)
3、判断是数组还是对象 typeof() object
4、建立相应的数组或对象 instanceof toString constructor
5、递归,循环往复
封装为方法:
1 function deepClone(origin,target){
2 for(var prop in origin){ //1、遍历对象
3 if(origin.hasOwnProperty(prop)){
4 if(origin[prop]!=="null"&&typeof(origin[prop])=='object'){ //2、判断是不是原始值
5 target[prop]=Object.prototype.toString.call(origin[prop])=="[object Array]" ? [] : {};
//3、判断是数组还是对象4、建立相应的数组或对象
6 deepClone(origin[prop],target[prop]); //5、递归
7 }else{
8 target[prop]=origin[prop];
9 }
10 }
11 }
12 return target;
13 }