0

我正在用javascript编写我的克隆函数。

该函数递归地克隆对象(避免循环引用)并且看起来效果很好,但是如果对象(在某种程度上)具有内置对象引用,当我尝试访问克隆对象的某些属性(看起来正确)时,我已经类型错误。

这是我使用 datetime 的简单示例(我知道克隆 datetime 对象有更有效的方法,但这不是我关心的问题,我需要做的是克隆一个通用的构建对象,datetimes 只是一个示例),它简化了我的真实克隆方法到只有浅拷贝函数和数组但深拷贝对象(内部数组和函数除外)并且不避免循环引用的方法。这只是错误的一个展示(我使用完整的克隆功能获得的错误相同)。

代码 :


        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 方法时会导致此类型错误:Uncaught TypeError: this is not a Date object。

但我仍然不明白为什么,克隆看起来像日期对象,我知道方法是共享的,我期待调用时出现奇怪的行为(方法指的是名为“日期”的对象,所以对象内部状态是“日期”而不是“克隆”)但不是错误。

那么为什么会出现这个错误呢?

感谢您的帮助,并为我的英语不好感到抱歉。


已编辑

根据向我建议的新想法(来自 RobG 和 jfriend00 在评论中发布的表格文章),我以这种方式重写了克隆功能。

                    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() ; 做一些改变。

非常感谢您的帮助。

4

1 回答 1

1

当您的对象是除了普通对象(如 Date 对象)之外的其他类型的对象时,您不是在创建克隆的 Date 对象,而是在创建普通对象。

此外,当您将属性复制到克隆对象时,您只是直接在对象上复制属性,而不是原型链中的属性,因为这是Object.getOwnpPropertyNames()返回的内容。因此,您克隆的 Date 对象没有任何 Date 方法。

根据 RobG 的建议,在返回之前添加第一行:

result.__proto__ = obj.__proto__;
return result ;
于 2013-06-03T23:59:07.313 回答