真正的Javascript深拷贝(不仅拷贝多个层级的值,还拷贝了类型)

参考文章:

1、js如何判断一个对象是不是Array?

2、实现JS数组的深拷贝

参考文章2的深拷贝代码如下:

function getType(o)
    {
        var _t;
        return ((_t = typeof(o)) == "object" ? o==null && "null" || Object.prototype.toString.call(o).slice(8,-1):_t).toLowerCase();
    }
    function extend(destination,source)
    {
        for(var p in source)
        {
            if(getType(source[p])=="array"||getType(source[p])=="object")
            {
                destination[p]=getType(source[p])=="array"?[]:{};
                arguments.callee(destination[p],source[p]);
            }
            else
            {
                destination[p]=source[p];
            }
        }
    }
    var test={a:"ss",b:"dd",c:{d:"css",e:"cdd"}};
    var test1={};
    extend(test1,test);
    test1.c.d="change"; //改变test1的c属性对象的d属性
    alert(test.c.d);  //不影响test

  假如:

var test={a:"ss",b:"dd",c:{d:"css",e:"cdd"}};
var test1=[];//使用该方法深拷贝,必须先定义拷贝到的对象,并且初始化
extend(test1,test);
test1.c.d="change"; //改变test1的c属性对象的d属性
alert(test.c.d);  //不影响test
这样做,的确也把test的数据复制过来了,而且,修改test1.c.d也不会对test造成影响,但是接下来的问题来了,test1的类型改变了,这个时候,我们按照原类型去处理,比如使用array的push方法,就会出错了,chrome监视情况如下
代码:

Chrome对象监视

无废话,正确代码如下

Ext.namespace("GTP.BI");
GTP.BI.Util = {};

GTP.BI.Util.getType = function (o) {

    var _t;
    return ((_t = typeof (o)) == "object" ? o == null && "null" || Object.prototype.toString.call(o).slice(8, -1) : _t).toLowerCase();
};

GTP.BI.Util.copy = function (source) {
    var destination = GTP.BI.Util.getType(source) == "array" ? [] : {}; //呵呵,联想到了Ext.extend方法
    for (var p in source) {
        if (GTP.BI.Util.getType(source[p]) == "array" || GTP.BI.Util.getType(source[p]) == "object") {
            destination[p] = GTP.BI.Util.getType(source[p]) == "array" ? [] : {};
            destination[p] = arguments.callee(source[p]);
        }
        else {
            destination[p] = source[p];
        }
    }
    return destination;
}


var test = { a: "ss", b: "dd", c: { d: "css", e: "cdd"} };
var test1 = [];
test1 = GTP.BI.Util.copy(test);
test1.c.d = "change"; //改变test1的c属性对象的d属性
alert(test.c.d); //不影响test

重要说明:test1 此时也为Object,它和初始化类型毫无关系。其实这里根本就不需要初始化,当然,若是初始化了,在这里不仅深拷贝了值,而且也拷贝了类型,将test1的初始化值和类型完全覆盖(这样的才是深拷贝么,哇哈哈)。

相对于参考文章二,其实做出的修改很小,主要是添加了命名空间(使用Extjs),另外,改了一下函数,在实现拷贝的时候,不需要传入要拷贝到的地方(destination),而采取动态生成destination对象,解决使用参考文章2中以下问题:

1、拷贝时需要初始化destination类型

2、若初始化错destination类型,会导致拷贝后类型变化的问题。

posted on 2012-07-17 20:19  zhangxuhui  阅读(646)  评论(0编辑  收藏  举报