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 }