前言
之前有人问我如何克隆一个JS对象,我当时没答上来;过后我查资料弄懂了这个问题,现在整理成文。
正文
JavaScript的一切实例都是对象,但他们也分为原始类型和引用类型。原始类型对象指的是字符串(String
)、数值(Number
)、布尔值(Boolean
)、undefined
、null
,引用类型对象指的是数组(Array
)、对象(Object
)、函数(Function
)。
既然对象分为这两类,他们的复制克隆也是有差别的。普通对象存储的是对象的实际数据,而引用对象存储的是对象的引用地址,而把对象的实际内容单独存放。下面我们就来看看他们克隆的区别。
原始类型对象的克隆
字符串的克隆
1 2 3 4 5 6
| var x="abc"; var y=x; y="xyz"; alert(x); // "abc" alert(y); // "xyz"
|
数值的克隆
1 2 3 4 5 6
| var x=1; var y=x; y=2; alert(x); // 1 alert(y); // 2
|
布尔值的克隆
1 2 3 4 5 6
| var x=true; var y=x; y=false; alert(x); // true alert(y); // false
|
我们可以看出来原始类型的克隆很简单,只需要一个=
赋值就可以了;undefined
、null
也是同理。
引用类型的对象克隆
数值的克隆
如果采用普通克隆:
1 2 3 4 5 6
| var x=[1,2]; var y=x; y.push(3); alert(x); // 1,2,3 alert(y); // 1,2,3
|
由上可知,原始数组x,克隆数组y,修改了克隆数组y,但也同时修改了原始数组x,这就是引用对象的特点。那么怎样才能达到完整的数组克隆呢?
1 2 3 4 5 6 7 8 9 10 11 12
| var x=[1,2]; var y=[]; var i=0; var j=x.length; for(;i<j;i++) { y[i]=x[i]; } y.push(3); console.log(x); // [1,2] console.log(y); // [1,2,3]
|
这样,两个数值就互不干扰,实现了完整数组克隆。
对象的克隆
和数组的克隆同理,对象的完整克隆如下:
1 2 3 4 5 6 7 8 9 10 11
| var x={a:2,b:4}; var y={}; var i; for(i in x) { y[i]=x[i]; } y.c=6; console.log(x); // Object {a: 2, b: 4} console.log(y); // Object {a: 2, b: 4, c: 6}
|
函数的克隆
1 2 3 4 5 6
| var x=function(){alert(1);}; var y=x; y=function(){alert(2);}; console.log(x); // function(){alert(1);}; console.log(y); // function(){alert(2);};
|
函数的克隆与原始类型对象克隆的方式类似;只需要使用=
就可以了。
总结
根据上面的情况,另外,克隆引用对象必须采用完整克隆(深度克隆),包括对象的值也是一个对象也要进行完整克隆(深度克隆)。所以,我们可以总结并封装一个通用的克隆方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| function clone(obj){ var o,i,j,k; if(typeof(obj)!=="object" || obj===null)return obj; if(obj instanceof Array){ o=[]; i=0;j=obj.length; for(;i<j;i++){ if(typeof(obj[i])==="object" && obj[i]!=null){ o[i]=clone(obj[i]); }else{ o[i]=obj[i]; } } }else{ o={}; for(i in obj){ if(typeof(obj[i])==="object" && obj[i]!==null){ o[i]=clone(obj[i]); }else{ o[i]=obj[i]; } } } return o; }
|