您的位置:首页 > Web前端 > JavaScript

js对象的深度克隆

2016-11-05 12:12 288 查看

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))

这里是用于处理字面量问题的。

自述

小白一枚,代码可能漏洞百出,大家不喜可提点一下,但勿喷,会打击伦家写博客的热情滴。。。。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  js 对象