如何實現 JavaScript對象的深拷貝?
发布于 3年前 作者 byvoid 2519 次浏览

如何實現 JavaScript 對象的深拷貝?需要複製後的對象是全新的,所有的成員包括成員函數在內。

14 回复
function $clone(origin) {
    if (typeof origin != "object") {
        return origin;
    }
    var cloned;
    if (origin instanceof Array) {
        cloned = [];
        for ( var i = 0; i < origin.length; i++) {
            if (typeof origin[i] == "object") {
                cloned[i] = $clone(origin[i]);
            }
            else {
                cloned[i] = origin[i];
            }
        }
    }
    else {
        cloned = {};
        for ( var j in origin) {
            if (typeof origin[j] == "object") {
                cloned[j] = $clone(origin[j]);
            }
            else {
                cloned[j] = origin[j];
            }
        }
    }
    return cloned;
};

這個無法拷貝函數啊

@byvoid 这个我用来做继承用的,比如Child.prototype = $clone(Parent.prototype),函数是可以拷贝过去的.

@sumory 函數不是深拷貝啊,而且成員的 instanceof 不可用了。

@byvoid 你确定没有搞错? 测试下这个:

function Test() {
    this.name = 'test';
}

function FatherTest() {
    
}

FatherTest.prototype.parts = [5,1,2];
FatherTest.prototype.printM = function(){
    print('this is printM from Father:'+ this.sex);
};

Test.prototype = $clone(FatherTest.prototype);//深入拷贝
Test.prototype.sex = 'male';

var test = new Test();
print('-------key in test--------');
for(var key in test){
    print(key +':'+test[key]);
}
print('-------test继承的方法--------');
test.sex = 'changed sex';
test.printM();

print('-------改变test的数组--------');
test.parts.push(3);
print(test.parts);
var father= new FatherTest();
print(father.parts);//不再会被test.parts.push(3);影响

print('-------instanceof--------');
print(test.parts instanceof Array);

看下结果,可以解答你的问题了

@sumory 這個實現對於函數類型還是淺拷貝,沒有真正複製一個函數。另外試試拷貝過的Date,instanceof不管用。還有,互相引用的兩個對象會遞歸到棧溢出。

@byvoid 我试了下Date类型的确实不能正确instanceof了;不知道你说的“栈溢出”的场景是?

@byvoid 请问为何要拷贝Date,Date是js中的引用类型,如何去复制,就像你无法去复制Object一样。另你所说的instanceof,请参考我的代码。

    function ss(){
    this.name='ss';
    this.test=['a','b','c'];
}
ss.prototype.age='12';
ss.prototype.sayName=function(){
    alert(this.name);
}
function subObject(o){
    function b(){};
    b.prototype=o;
    return new b();
}
var cc=subObject(new ss());
var dd=subObject(new ss());
cc.name='I\'m cc';
dd.test.push('d');
for (var key in cc){
    console.log(key+':'+cc[key]);
}
for (var key in dd){
    console.log(key+':'+dd[key]);
}

var ee=subObject(new Date());
alert(ee instanceof Date); //true 没有继承任何date的方法

@sumory 這個例子,無論複製 obj1 還是 obj2 ,都會棧溢出。

var obj1 = {
  ref: null
};

var obj2 = {
  ref: obj1
};

obj1.ref = obj2;

@byvoid 循环是普遍问题吧,应该避免这样的编程方式并加检测机制的,就是不太了解js里应该怎么写

碰到函数时用匿名函数包一层: (function (c, a) { fn,apply(c, a); }(context, arg)) context为你的新上下文,其他的,你懂的

忘记return了,还要包一层。。。和bind一样的

return JSON.parse(JSON.stringify(origin));

这种只适用于Function以外的对象

回到顶部