鸟食轩

 Microsoft .NET[C#] MVP 2003
随笔 - 429, 文章 - 235, 评论 - 5529, 引用 - 356
数据加载中……

对JScript对象的实例Clone的一个实现

    刚才看见cmbscqhd关于'JS继承问题的研究',发现他的继承方法的问题出在对对象使用了shallow copy (this[i] = _childClass.prototype[i];)上。不过从他的代码中我发现了一个实现Clone很sexy的方法,于是写一个JScript类实例的的deep clone方法,和对JScript所支持对象(数据类型)的Clone详细比较。

    实现Clone最关键的就是要创建一个和原对象类型相同的对象,不然还叫什么Clone呢?然后再把原对象里的值Copy到目标对象,如果遇到值本身是对象的,还需要继续递归创建和复制数据。

    JScript对象实例的Clone方法代码如下:
<script language="javascript">
Object.prototype.Clone 
= function()
{
    
var objClone = new this.constructor();
    
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];
            }

        }

    }

    
if ( !objClone || ('' + objClone) == '' )
    
{
        
return (new String(this+ objClone) ? this : objClone;
    }

    
else
    
{
        objClone.toString 
= this.toString;
        
return objClone; 
    }
 
}
    
</script>

    这段代码中最关键的两点就是:var objClone = new this.constructor();和objClone[key] = this[key].Clone();。一个完成相同对象创建,一个完成了deep clone。最后那个判断到底是返回this还是返回objClone,是用来对对象类型或空Array的一个优化。这个Clone方法对所有(不包括Function、Global和Math)JScript对象实例的Clone效果分析如下:
  

    显现对于值类型这个Clone方法不能很好的工作:(,还有一个比较特殊的对象类型,就是Date,它也不能被正常的Clone。不过这个不是很严重的问题,要在Clone方法里面去判断被Clone的对象是不是Date、Boolean和Number相对来说是很容易的。我没有加到这个方法中去是为了保持这个方法的清爽,因为我们值类型本身是不存在Clone问题的,赋值即就是Clone了。

    附Clone方法的测试源代码:
<html>
<head>
    
<title>JScript Inherit Research</title>
    
<meta name="author" content="cmbscqhd;birdshome@博客园" />
</head>
<body>
    
<script language="javascript"></script>
    
<script language="javascript"></script>
</body>
</html>

posted on 2005-02-22 13:10 birdshome 阅读(9747) 评论(18)  编辑 收藏 网摘 所属分类: Jscript&Dhtml开发

评论

#1楼   回复  引用  查看    

为了感谢 鸟食轩 ,我帮你点了所有该页的广告。
2005-02-22 18:39 | 辣妹子      

#2楼   回复  引用    

:)
2005-02-22 21:57 | birdshome

#3楼   回复  引用    

你的Date对象测试恐怕有点问题。因为当对象运行到某一状态时,所谓克隆就是完全复制该对象及其克隆时刻的完全状态,因此对Date对象克隆前后,两者值当然是相等的,只要两者互不干扰即可!

即你的克隆方法对Date对象是成功的!

请审查我的克隆方法:
Object.prototype._clone = function()
{
if(this.nodeType)return this
var _type=typeof(this);
var _cst=this.constructor;
if(_type!="object" || this==null)return this;
if (_cst==Boolean || _cst==String || _cst==Number || _cst==Date ){return new _cst(this.valueOf())}
if (_cst==Array)
{
var objClone = new _cst;
for ( var key in this )
objClone[key] = typeof(this[key])=="object"?(this[key]!=null?this[key]._clone():this[key]):this[key];
return objClone;
}

var c = function(){};
c.prototype = this;
var _objclone=new c();
for(var i in _objclone)
{
var o = _objclone[i];
if (o!=null &&(o.constructor==Boolean || o.constructor==String || o.constructor==Number || o instanceof Date))
{_objclone[i]=new o.constructor(o.valueOf())}
else if(typeof(o)=="object")
{_objclone[i]=(o==null?o:o._clone());}
}
return _objclone;
};

#4楼   回复  引用    

“所谓克隆就是完全复制该对象及其克隆时刻的完全状态,因此对Date对象克隆前后,两者值当然是相等的,只要两者互不干扰即可!”,可是我的original和cloned的值不相等哦:(

还有,我做的那个Clone方法就是不想去判断到底被Clone的东西是啥东西,如果判断了对象是Date类型,直接new Date(dt.getTime)肯定就没有问题了。你的那个方法是不是太复杂了:}
2005-02-23 11:45 | birdshome

#5楼   回复  引用  查看    


var objClone = new this.constructor();

改为
var objClone = new this.constructor(this.valueOf());

好象应该是好的。

2005-03-19 13:50 | 麻袋      

#6楼[楼主]   回复  引用  查看    

@麻袋
能麻烦说一下好在哪里吗?我没有太看出来
2005-03-19 14:08 | birdshome      

#7楼   回复  引用  查看    

我试了一下,你上面说的问题好象没有了。
2005-03-19 14:19 | 麻袋      

#8楼   回复  引用  查看    

对于 date, boolean, number 这三种基本的数据类型,执行
var objClone = new this.constructor();
的时候,得到的是默认值。而真实的值又没有属性可引用到,所以,只能在初始化的时候,以参数形式赋默认值。
var objClone = new this.constructor(this.valueOf());
2005-03-19 14:25 | 麻袋      

#9楼   回复  引用  查看    

发现点问题(我写的),应该将第一句改为
var objClone;

if(this.constructor == Object)
objClone = new this.constructor();
else
objClone = new this.constructor(this.valueOf());


2005-03-19 16:34 | 麻袋      

#10楼   回复  引用  查看    

还有最后的
objClone.toString = this.toString;

还应该将Object中定义的其他方法也Copy
objClone.valueOf = this.valueOf;

在JScript中还应该加
objClone.toLocaleString = this.toLocaleString;
2005-03-19 16:49 | 麻袋      

#11楼[楼主]   回复  引用  查看    

@麻袋
,重新讨论了一下Clone的问题并参考了你的建议,'兼容值类型的JavaScript对象Clone方法'。
2005-03-20 16:04 | birdshome      

#12楼   回复  引用    

添加了这个方法后,任何对象执行 for in 循环都会多出一个 clone 成员,怎么处理?
2005-06-22 18:22 | 宇义[未注册用户]

#13楼   回复  引用    

@宇义
为什么要用for in语句呢?如果是确切的元素,使用数组,如果是mapping,尽量不要使用遍历。目前只能这样。
2005-06-22 21:01 | birdshome

#14楼   回复  引用    

虽然没有得到想要的答案,但是知道了这是mission impossible,我也就不再研究了。

我经常用 for in ,看来不是一个好习惯。

谢谢啦~
2005-06-23 01:07 | 宇义[未注册用户]

#15楼   回复  引用    

我想到了,可以把clone做成一个函数,而不是每个Object的方法,这样就不怕for in 中出现clone了,呵呵。
2005-06-24 00:30 | 宇义[未注册用户]

#16楼[楼主]   回复  引用  查看    

@宇义
你不加prototype方法,别人也还有可能添加prototype方法,所以我觉得使用for in是非常危险的,不推荐。
可以这样来安全遍历Object:http://www.cnblogs.com/birdshome/archive/2005/06/24/180609.html">http://www.cnblogs.com/birdshome/archive/2005/06/24/180609.html
2005-06-24 10:03 | birdshome      

#17楼   回复  引用  查看    

谢谢楼主提供这个学习机会!
真心的谢谢楼主!
2005-07-19 19:24 | 轩辕剑      

#18楼   回复  引用  查看    


给Object加prototype方法导致jquery在append()或insert等操作异常...
2007-09-23 20:23 | 无常      



发表评论

昵称: [登录] [注册]

主页:

邮箱:(仅博主可见)

评论内容:

  登录  注册

[使用Ctrl+Enter键快速提交评论]

0 107221




相关文章:

相关链接: