JS的浅拷贝和深拷贝

133 阅读2分钟

一、浅拷贝和深拷贝的定义

浅拷贝:浅拷贝只是拷贝一层更深层次对象级别的只拷贝引用。

深拷贝:深拷贝拷贝多层,每一级别的数据都会拷贝。

二、浅拷贝和深拷贝的区别

浅拷贝和深拷贝都创建出一个新的对象,但在复制对象属性的时候,行为就不一样

  1. 浅拷贝只复制属性指向某个对象的指针,而不复制对象本身,新旧对象还是共享同一块内存,修改对象属性会影响原对象
  2. 深拷贝会另外创造一个一模一样的对象,新对象跟原对象不共享内存,修改新对象不会改到原对象

三、浅拷贝的实现

    1. for···in只循环第一层
// 只复制第一层的浅拷贝
    function simpleCopy(obj1) {
        var obj2 = Array.isArray(obj1) ? [] : {};
        for (let i in obj1) {
            obj2[i] = obj1[i];
        }
        return obj2;
    }
    var obj1 = {
        a: 'A',
        b: 'B',
        c: {
            d: 'D'
        }
    }
    var obj2 = simpleCopy(obj1);
    obj2.a = 'C';
    obj2.c.d = 'E';
    console.log(obj1.a); // A
    console.log(obj2.a); // C
    console.log(obj1.c.d); // E
    console.log(obj2.c.d); // E
  1. Object.assign方法

ES6中的Object.assign方法,Object.assign是ES6的新函数。Object.assign() 方法可以把任意多个的源对象自身的可枚举属性拷贝给目标对象,然后返回目标对象。但是 Object.assign() 进行的是浅拷贝,拷贝的是对象的属性的引用,而不是对象本身。

    var obj1 = {
        a: "A",
        b: {
            a: "C",
            b: 21
        }
    };

    var cloneObj1 = Object.assign({}, obj1);
    cloneObj1.a = "DF";
    cloneObj1.b.a = "JK";
    console.log(obj1.a);  //A
    console.log(obj1.b.a); // JK
  1. 直接用=赋值 和 拓展运算符
    let a = ['A', 'B', 'C', 'D', 'E'],
        b = a;
    console.log(a === b); //true
    a[0] = 1;
    console.log(a, b); // 1 'B', 'C', 'D', 'E'
    
    const expandArr = ["A", "B", "C"];
    const expandArrs = [...expandArr];
    expandArr[1] = "JK";
    console.log(expandArr); // ["A", "JK", "C"]
    console.log(expandArrs); // ["A", "B", "C"]

四、深拷贝的实现

  1. 采用递归去拷贝所有层级属性
    function deepClone(obj) {
        let objClone = Array.isArray(obj) ? [] : {};
        if (obj && typeof obj === "object") {
            for (key in obj) {
                if (obj.hasOwnProperty(key)) {
                    //判断ojb子元素是否为对象,如果是,递归复制
                    if (obj[key] && typeof obj[key] === "object") {
                        objClone[key] = deepClone(obj[key]);
                    } else {
                        //如果不是,简单复制
                        objClone[key] = obj[key];
                    }
                }
            }
        }
        return objClone;
    }
    let a = ['A', 'B', 'C', 'D'],
        b = deepClone(a);
    a[0] = 'J';
    console.log(a, b); // a['J', 'B', 'C', 'D']  b ['A', 'B', 'C', 'D']
  1. 利用 JSON 对象实现深拷贝

JSON.stringify把对象转成字符串,再用JSON.parse把字符串转成新的对象。

    // 深拷贝拷贝多层, 每一级别的数据都会拷贝.
    var obj = {
        id: 1,
        name: 'andy',
        msg: {
            age: 18
        },
        color: ['pink', 'red']
    };

    // 2. 利用 JSON 对象
    function deepCopy(obj) {
        let _obj = JSON.stringify(obj);
        let newObj = JSON.parse(_obj);
        return newObj;
    }

    let newObj = deepCopy(obj);
    newObj.msg.age = 22;
    console.log(newObj);  //  newObj.msg.age = 22
    console.log(obj);  // obj.msg.age 还是等于 18 没有改变

image.png

五、总结

浅拷贝的时候如果数据是基本数据类型,那么就如同直接赋值那种,会拷贝其本身,如果除了基本数据类型之外还有一层对象,那么对于浅拷贝而言就只能拷贝其引用,对象的改变会反应到拷贝对象上,但是深拷贝就会拷贝多层,即使是嵌套了对象,也会都拷贝出来。