js对象的深度克隆
基本类型和引用类型的复制
对于复制相信大家都不陌生,复制了有两种情况:引用类型的复制与基本类型的复制。其中基本类型的复制:在变量对象上创建一个新值,然后将该值复制到新值分配的位置上去。这两个变量可以参与任何操作而不互相影响。且二者都存储在栈内存中。
而对于引用类型的复制,传递的仅仅是一个指向原引用类型的的地址(类似指针的概念)。他是仅仅是对地址的引用,而非间接寻址。这两个变量参与任何操作都会互相影响,原对象存储于堆内存,复制后对象存储于栈内存中。
引用类型的深度克隆
这两天因为准备面试所以刷了一下题。遇到一个出镜率很高的boy:对象的深度克隆。本以为拿来网上别人写的答案理解一下就可以,但在运行代码时总会出现或多或少的问题。所以自己又花了半天时间调试出一个自己的clone。可能会有或多或少的情况没有考虑到,希望大家多多指点。
参考案例
首先,我先放我参考的一个博友 u010599762(http://m.blog.csdn.net/article/details?id=40144017)的clone方法。
{
var o;
if(obj1.constructor==Object)
{
o = new obj1.constructor() ;
}
else
{
o = new obj1.constructor(obj1.valueOf())
}
for(var key in obj1)
{
if(obj1[key]!=o[key])
{
if(typeof obj1[key] =="object"&&obj1[key]!=null)
o[key] = clone2(obj1[key]) ;
else
o[key] = obj1[key] ;
}
}
return o ;
}
测试用例:
function Obj1(){
this.a = 1 ;
this.b = 2 ;
this.view = {
'name':'zhangsan'
};
}
Obj1.prototype.arr = [1,2,3,4] ;
var oNew = new Obj1();
var copy = clone2(oNew) ;
copy.view = {
age : 10
} ;
console.log('copy:'+copy.view);
console.log('oNew:'+oNew.view);
var oNew2 = {
name : 'pan',
position : 'student'
}
var copy2 = clone2(oNew2);
copy2.name = 'wang';
console.log(copy2.name);//'wang'
console.log(oNew2.name);//'pan'
问题一
对于普通对象的克隆是没什么问题,但是对于数组的克隆处理的就有点问题了。在测试用例中
Obj1.prototype.arr = [1,2,3,4] ;
var oNew = new Obj1();
var copy = clone2(oNew) ;
我用firebug调试了一下:
发现会出现这样的问题:copy 的数组对象arr 被克隆成了[[1,2,3,4]]。这是由于o = new obj1.constructor(obj1.valueOf());将传入数组作为一个对象进行处理了。
问题二
而且对于以字面量形式生成的对象也没有解决。
测试代码:
var oNew2 = {
name : 'pan',
position : 'student'
}
var copy2 = clone2(oNew2);
console.log(copy2);
console.log(oNew2);
修改过的代码
于是帮我把程序进行了修改:
function clone2(obj1) {
var o;
if(obj1.constructor==Object){//当obj1为字面量形式生成对象情况。
o = new obj1.constructor() ;
for(var key in obj1)
{
if(o[key] != obj1[key]) {
if(typeof obj1[key] =="object"&&obj1[key]!=null)
o[key] = clone2(obj1[key]) ;
else
o[key] = obj1[key] ;
}
}
} else if(obj1.constructor == Array) {
//obj1是数组时的情况
var array = [];
obj1.forEach(function(value) {
if(typeof(value) != "object")
array.push(value);//数组元素为基本类型
else
array.push(clone2(value));//数组元素为引用类型
});
o = array;
} else {//以构造函数形式new出的对象
o = new obj1.constructor(obj1.valueOf());
//当obj1为内置对象时obj1.valueOf()的参数作用才真正使用。否则,这里传递的参数就不会被用到。
for(var key in obj1){
if(!obj1.hasOwnProperty(key)) {
if(typeof obj1[key] =="object"&&obj1[key]!=null)
o[key] = clone2(obj1[key]) ;
else
o[key] = obj1[key] ;
}
}
}
return o ;
}
这里有一点需要注意。在处理字面量对象(obj1.constructor==Object)与构造函数对象时我们队对象本身属性的判断方式不同。
对于字面量对象:
if(o[key] != obj1[key])
对于构造函数对象:
if(!obj1.hasOwnProperty(key))
这里是用于处理字面量问题的。
自述
小白一枚,代码可能漏洞百出,大家不喜可提点一下,但勿喷,会打击伦家写博客的热情滴。。。。