现在的位置: 首页 > 综合 > 正文

有关对象克隆和使用了prototype后,for..in语句的问题

2012年12月06日 ⁄ 综合 ⁄ 共 2553字 ⁄ 字号 评论关闭

今天遇到个问题,开始还觉得很奇怪,后来才恍然大悟,原来是对象克隆里面浅拷贝和深拷贝的问题。看书的时候意思知道,可就是不能联想到能用在哪里?以致出现bug后才发觉玄机原来在这里。问题是这样出现的:

var strTree={"000501":{"id":"127","name":"人事下载","hasChild":true,"isLast":false,"changeFlag":0,"isFolder":true},
"000502":{"id":"128","name":"劳资下载","hasChild":false,"isLast":true,"changeFlag":0,"isFolder":false}}
;
strTree[
"000601"]=strTree["000501"];
strTree[
"000601"].changeFlag=1;

结果发现strTree["000501"]和strTree["000601"]的changeFlag均变成了1,原因很直观,是由两个json对象引用的是同一个对象地址所致,当然可以采用重新申请对象和地址的初始化方式解决不同引用的问题,然后对属性逐一赋值,如:

function exchangeJson(divObj,id1,id2)
{
            
if(strTree[id1]==undefined)
                strTree[id1]
={"id":"0","name":"","hasChild":false,"isLast":false,"isFolder":false,"changeFlag":1};
            strTree[id1].name
=strTree[id2].name;
            strTree[id1].hasChild
=strTree[id2].hasChild;
            strTree[id1].isLast
=strTree[id2].isLast;
            strTree[id1].isFolder
=strTree[id2].isFolder;
}

但显然,这不够好,只针对了strTree的特定结构,丝毫不具备扩展性和通用性,依靠原型的方法解决所有同一类型的问题才是正解,在自己编写代码之前,在网上查了下,在鸟食轩大大那里看到了已经非常完善的解决方法,copy之(当然,可不是囫囵吞枣)

 // Authors Birdshome, 麻袋@博客园  
 Object.prototype.Clone = function()
 
{
    
var objClone;
    
if ( this.constructor == Object ) objClone = new this.constructor(); 
    
else objClone = new this.constructor(this.valueOf()); 
    
for ( var key in this )
    
{
        
if ( objClone[key] != this[key] )
        

            
if ( typeof(this[key]) == 'object' )
            

                objClone[key] 
= this[key].Clone();
            }

            
else
            
{
                objClone[key] 
= this[key];
            }

        }

    }

    objClone.toString 
= this.toString;
    objClone.valueOf 
= this.valueOf;
    
return objClone; 
 }
    

但在我的应用中,却又出现了一个很郁闷的问题,因为用到了原型扩展,而我应用中对strTree是用for..in循环来处理的。

for(element in strTree)
{
   strTree[element].name
=
   
}

却出现了问题,element中多了个值,即原型扩展后的方法名"Clone",导致程序报错,这让我很不爽,难道需要加上if(element!=="Clone") then...的处理吗?随着应用的深入,prototype还可能随时会扩展,显然这样不行,for..in语句是特定为了遍历具有不规则下标的strTree而采用的,换成其他循环似乎也不可行,网上有人提出,还未想到好的解决办法,正不爽中...。望赐教!

昨天鸟食轩大大给我回邮件了,提供了一种很好的办法,那就是利用object.constructor来区分prototype扩展的方法和expando,对于constructor,以前并没有在意,它有多大用处,帮助手册上的解释是:constructor 属性是所有具有 prototype 的对象的成员。它们包括除 Global 和 Math 对象以外的所有 JScript 固有对象。constructor 属性保存了对构造特定对象实例的函数的引用。也就是说通过设置一个var obj=new sourceObj.constructor();可以将object的prototypte扩展方法连同实例函数名赋值给obj了,而示例中的json对象成员将不会赋值过去,所以可以这样应用:

var obj = new this.jsonTree.constructor();
for(flag in this.jsonTree)
{
    
if(obj[flag]!=this.jsonTree[flag])
       
}

通用的问题也解决了,也不害怕prototype再有扩展了。搞定!

问题本身没什么,但反映出来的问题却不可小视,那就是自己对原理性的东西关注不够,解决问题的方式也就只是从网上搜,或者求助于别人了,当然不是说这样不好,但要创造,要开创性做一些东西的话,显然这样是不可能办到的,给自己提个醒吧。

抱歉!评论已关闭.