刚才看见
关于'
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"
>
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
>

<
script
language
="javascript"
>
document.write("<table border='1' style='border-collapse: collapse;'>"
+ '<tr><th>Data Type</th><th>Original</th><th>Cloned'
+ '</th><th>Modified</th><th>Status</th></tr>');
var Render = function(type, original, cloned, modified, isSuccess)

{
var str = '<tr><td>' + type + '</td><td>' + original + '</td><td>'
+ cloned + '</td><td>' + modified + '</td><td align="center">'
+ '<span style="color:' + (isSuccess ? 'blue' : 'red') + ';">'
+ (isSuccess ? ':):):)' : ':(:(:(') + '</span></td></tr>';
document.write(str);
}

var obj =

{
abc : 'abc',
faint : ['f', 'a', 'i', 'n', 't'],
toString : function()

{
return 'abc:' + this.abc + ', faint:[' + this.faint + ']';
}
};
var objClone = obj.Clone();
var objClone2 = obj.Clone();
objClone2.abc = 'def';
for ( var i=0 ; i < objClone2.faint.length ; ++i ) objClone2.faint[i] = '-';
Render('Object', obj, objClone, objClone2, true);
var dt = new Date();
for ( var i=0 ; i < 300000 ; i++ ) new Object();
var dtClone = dt.Clone();
for ( var i=0 ; i < 300000 ; i++ ) new Object();
var dtClone2 = dt.Clone();
dtClone2.setYear(2006);
Render('Date', dt.getTime(), dtClone.getTime(), dtClone2.getTime(), false);
var ary = ['a', 'r', 'y'];
var aryClone = ary.Clone();
var aryClone2 = ary.Clone();
aryClone2.push('!!!');
Render('Array', ary, aryClone, aryClone2, true);
var aryEx = [];
var aryExClone = aryEx.Clone();
var aryExClone2 = aryEx.Clone();
aryExClone2.push('ary');
Render('Array(null)', aryEx, aryExClone, aryExClone2, true);

var str = 'faint';
var strClone = str.Clone();
var strClone2 = str.Clone();
strClone2 = 'layala';
Render('String', str, strClone, strClone2, true);
var bool = true;
var boolClone = bool.Clone();
var boolClone2 = bool.Clone();
boolClone2 = false;
Render('Boolean', bool, boolClone, boolClone2, false);
var num = 100;
var numClone = num.Clone();
var numClone2 = num.Clone();
Render('Number', num, numClone, numClone2, false);
var err = new Error(100, 'error!');
var errClone = err.Clone();
var errClone2 = err.Clone();
errClone2.number = 10000;
errClone2.message = 'ERROR!';

Error.prototype.ToString = function()
{ return this.number + ', ' + this.message; };
Render('Error', err.ToString(), errClone.ToString(), errClone2.ToString(), true);
document.write('</table>');
// Function Global, Math ,Regex
</
script
>
</
body
>
</
html
>