我正在用javascript编写我的克隆函数。
该函数递归克隆对象(避免循环引用)并且看起来效果很好,但是如果对象(在某个级别)具有内置对象引用,当我尝试访问克隆对象的某些属性时(看起来正确)我有一个类型错误。
这是我使用datetime的简单示例(我知道克隆日期时间对象有更多有效的方法,但这不是我关注的,我需要做的是克隆一个通用的构建对象,日期时间只是一个例子)我真正的克隆方法,只有浅拷贝函数和数组但深拷贝对象(内部数组和函数除外)并且不能避免循环引用。 这只是错误的一个调整(我使用完整克隆函数获得的相同错误)。
代码:
var date = new Date () ;
var dateProto = date.__proto__ ;
var cloned = {} ;
var clonedProto = {} ;
function clone ( obj )
{
if ( obj instanceof Array )
return [] ;
if ( obj instanceof Function )
return obj ;
if ( obj instanceof Object )
{
var result = {} ;
var elems = Object.getOwnPropertyNames(obj) ;
var len = elems.length ;
for ( var i = 0 ; i < len ; i++ )
{
var prop = elems[i] ;
var elem = obj[prop] ;
result [ prop ] = clone ( elem ) ;
}
return result ;
}
return obj ;
}
cloned = clone ( date ) ;
clonedProto = clone ( dateProto ) ;
cloned.__proto__ = clonedProto ;
alert ( cloned.getDay() );
但是当尝试访问getDay方法时,这会导致此类型错误: 未捕获的TypeError:这不是Date对象。
但是我仍然不明白为什么,克隆看起来像日期对象,我知道方法是共享的,我在调用时期待奇怪的行为(方法引用称为“日期”的对象,因此对象内部状态是“日期“不”克隆“)但不是错误。
那么为什么会出现这个错误?
感谢您的帮助,抱歉我的英语不好。
被修改
根据建议的新想法(包括由评论中的jfriend00发布的RobG和表格文章)给我,我就这样重写了克隆功能。
function clone ( obj )
{
if ( obj instanceof Array )
return [] ;
if ( obj instanceof Function )
return obj ;
if ( obj instanceof Object )
{
var result = new obj.constructor() ;
result.__proto__ = clone ( obj.__proto__ ) ;
var elems = Object.getOwnPropertyNames(obj) ;
var len = elems.length ;
for ( var i = 0 ; i < len ; i++ )
{
var prop = elems[i] ;
var elem = obj[prop] ;
result [ prop ] = clone ( elem ) ;
}
return result ;
}
return obj ;
}
现在似乎工作我的预期,但我不明白为什么这段代码: var result = new obj.constructor(); 有所作为。
非常感谢你的帮助。
答案 0 :(得分:1)
当您的对象是普通对象(如Date对象)之外的其他类型的对象时,您不是在创建克隆的Date对象,而是创建一个普通对象。
此外,当您将属性复制到克隆对象时,您只是直接在对象上复制属性,而不是原型链中的属性,因为Object.getOwnpPropertyNames()
返回的属性。因此,克隆的Date对象没有Date方法。
根据RobG的建议,在返回之前添加第一行:
result.__proto__ = obj.__proto__;
return result ;