怎样拷贝对象(深/浅拷贝)

169 阅读1分钟
原文链接: github.com

#说到拷贝对象,大家可能会先想到Object.assign这个方法,但是它并不是那么完美,它只会拷贝一层对象,如果对象里面还有对象它就引用了原来的对象。具体看下面代码

  1. 一层拷贝没任何问题
let obj = {
    aa: 11
}

let newObj = Object.assign({}, obj);
obj.aa = 22;

console.log(newObj.aa); //11
console.log(obj.aa); //22
  1. 多层拷贝就变成引用了
let obj = {
    aa: 11,
    bb: {
        cc: 22
    }
}

let newObj = Object.assign({}, obj);
obj.bb.cc = 33;

console.log(newObj.bb.cc); //33
console.log(obj.bb.cc); //33

像上面这样拷贝对象我们叫浅拷贝,其实我们也可以通过for-in循环来模拟浅拷贝

let obj = {
    aa: 11,
    bb: {
        cc: 22
    }
}

let newObj = {};
for (const key in obj) {
    newObj[key] = obj[key];
}

下面简单实现一个对象的深拷贝

function clone(Obj) {  
    var buf;    
    if (Obj instanceof Array) {    
        buf = [];  // 创建一个空的数组   
           
        var i = Obj.length;    
        while (i--) {      
            buf[i] = clone(Obj[i]);    
        }    
        return buf;  
    } else if (Obj instanceof Object) {    
        buf = {};  // 创建一个空对象     
          
        for (var k in Obj) {  // 为这个对象添加新的属性   
                 
            buf[k] = clone(Obj[k]);    
        }    
        return buf;  
    } else {    
        return Obj;  
    }
}

比较详细的写法可以像下面这样

let obj = {aa: 11, bb: {cc: [0, [1]]}}

function copyObj(options) {
    return copy(options)
}

function copyAry(ary) {
    let newAry = []
    for (const item of ary) {
        let value = item;
        if (Object.prototype.toString.call(value) === "[object Object]") value = copyObj(value);
        if (Object.prototype.toString.call(value) === "[object Array]") value = copyAry(value);
        newAry.push(value);
    }
    return newAry;
}

function copy(obj) {
    let newObj = {};
    for (const key in obj) {
        let value = obj[key];
        if (Object.prototype.toString.call(value) === "[object Object]") value = copyObj(value);
        if (Object.prototype.toString.call(value) === "[object Array]") value = copyAry(value);
        newObj[key] = value;
    }
    return newObj;
}


let newObj = copyObj(obj);

// 测试
obj.bb.cc[1][0] = 666;
console.log(newObj.bb.cc[1][0]) //1
console.log(obj.bb.cc[1][0]) //666