浅拷贝和深拷贝三种方法

  1. 什么是深拷贝和浅拷贝:

    深拷贝针对的是复杂的 Object 数据类型,深拷贝需要将属性的各个层级都要拷贝过来。
    深拷贝将另一个对象的属性值拷贝过来之后,另一个对象的属性值并不受到影响,因为它自己在堆中开辟了自己的内存区域,不受外界干扰。

    浅拷贝主要拷贝的是对象的引用值,当改变对象的值,另一个对象的值也会发生变化。

    例子:js中的slice() 方法不能达到完全的深拷贝, 一维数组可以深拷贝,当改变a[0]的值后,打印处a的值改变,b的值并不受到影响,仍然是[1,2,3,4]。
    //一维数组的slice
    let a = [1, 2, 3, 4],
      b = a.slice();
    
    a[0] = 5;
    console.log(a);  //[ 5, 2, 3, 4 ]
    console.log(b);  //[ 1, 2, 3, 4 ]
    
    b[0] = 10;
    console.log(a); //[ 5, 2, 3, 4 ]
    console.log(b); //[ 10, 2, 3, 4 ]
    换一个多层级的数组:
    let a=[0,1,[2,3],4],
    b = a.slice();
    
    a[0]=2;
    a[2][0]=1;
    console.log(a);  //[ 2, 1, [ 1, 3 ], 4 ]
    console.log(b);  //[ 0, 1, [ 1, 3 ], 4 ]
    二维数组中slice() 拷贝并不彻底,二级属性没能拷贝成功,b仍脱离不了a的控制,说明slice不是真正的深拷贝。
    同理,concat 方法不是真正的深拷贝,也存在这样的情况
  2. 扩展运算符和 Object.assign() 都不是深拷贝
    扩展运算符:
    let outObj = {
        inobj: {
            a: 1,
            b: 2
        }
    }
    let newObj = {
        ...outObj
    }
    newObj.inobj.a = 2
    console.log(outObj);   //{ inobj: { a: 2, b: 2 } }

    Object.assign():浅拷贝

    let outObj = {
        inObj:{a:1,b:2}
    }
    let newObj = Object.assign({},outObj);
    newObj.inObj.a = 2;
    console.log(outObj);    //{ inObj: { a: 2, b: 2 } }

    只有一层嵌套是可以的,所以能否深拷贝要看数据结构怎么设计的。

  3. 实现深拷贝的三个办法:
    JSON.parse(JSON.stringfy()): 这个方法很简单 ,但不能拷贝函数。遇到正则会变成对象。

    let outObj = {
        foo: 1,
        inObj: { a: 1, b: 2 },
        bar: function () { }
    }
    let newObj = JSON.parse(JSON.stringify(outObj));
    
    console.log(newObj);   //{ foo: 1, inObj: { a: 1, b: 2 } }
    
    newObj.inObj.a = 2;
    
    console.log(outObj);  //{ foo: 1, inObj: { a: 1, b: 2 }, bar: [Function: bar] }
    console.log(newObj)   //{ foo: 1, inObj: { a: 2, b: 2 } }

  4. 用 for...in 遍历和复制实现一个深拷贝方法:

    const deepClone = (obj) => {
        if (typeof obj !== 'object') return
        let newObj = obj instanceof Array ? [] : {}
        for (let key in obj) {
            if (typeof obj[key] === 'object') {
                newObj[key] = deepClone(obj[key])
            } else {
                newObj[key] = obj[key]
            }
        }
        return newObj
    }
    

    将上面的例子拿来验一下:

    let outObj = {
        foo: 1,
        inObj: { a: 1, b: 2 },
        bar: function () { }
    }
    let objCopy = deepClone(outObj);
    console.log(objCopy);    //{ foo: 1, inObj: { a: 1, b: 2 }, bar: [Function: bar] }
    
    objCopy.inObj.a = 2;
    console.log(objCopy);    //{ foo: 1, inObj: { a: 2, b: 2 }, bar: [Function: bar] }
    console.log(outObj);    //{ foo: 1, inObj: { a: 1, b: 2 }, bar: [Function: bar] }

    复杂对象的处理:

    const allRoomPos = {
        "幻灵": {
            'p1': { 'x': 1000, 'y': 615 },
            'p2': { 'x': 1000, 'y': 670 },
            'p3': { 'x': 935, 'y': 670 },
            'p4': { 'x': 935, 'y': 615 }
        },
        "仙游": {
            'p1': { 'x': 1000, 'y': 515 },
            'p2': { 'x': 1000, 'y': 580 },
            'p3': { 'x': 935, 'y': 580 },
            'p4': { 'x': 935, 'y': 515 }
        },
    }
    
    let copyRoompos = deepClone(allRoomPos);
    console.log(copyRoompos);
    /*
    { '幻灵':
       { p1: { x: 1000, y: 615 },
         p2: { x: 1000, y: 670 },
         p3: { x: 935, y: 670 },
         p4: { x: 935, y: 615 } },
      '仙游':
       { p1: { x: 1000, y: 515 },
         p2: { x: 1000, y: 580 },
         p3: { x: 935, y: 580 },
         p4: { x: 935, y: 515 } } }
    */
    
    
    console.log(allRoomPos)
    /*
    { '幻灵':
       { p1: { x: 1000, y: 615 },
         p2: { x: 1000, y: 670 },
         p3: { x: 935, y: 670 },
         p4: { x: 935, y: 615 } },
      '仙游':
       { p1: { x: 1000, y: 515 },
         p2: { x: 1000, y: 580 },
         p3: { x: 935, y: 580 },
         p4: { x: 935, y: 515 } } }
    */
  5.  利用数组的 Array.prototype.forEach 和 ECMAScript 5 中的Object.* 函数实现深拷贝:

    var deepClone = function (obj) {
      var copy = Object.create(Object.getPrototypeOf(obj));
      var propNames = Object.getOwnPropertyNames(obj);
    
      propNames.forEach(function (name) {
        var desc = Object.getOwnPropertyDescriptor(obj, name);
        Object.defineProperty(copy, name, desc);
      });
      return copy;
    }
    
    var obj1 = {
      family: { brother: "wangzhipeng", father: "wanglicai", mother: "sunaiyun" },
      name: "gino",
      sex: "male",
      age: "27"
    };
    
    var obj2 = deepClone(obj1);
    obj1.sex = "close";
    console.log(obj1);
    /*
    { family:
       { brother: 'wangzhipeng',
         father: 'wanglicai',
         mother: 'sunaiyun' },
      name: 'gino',
      sex: 'close',
      age: '27' }
    */
    
    
    console.log(obj2);
    /*
    { family:
       { brother: 'wangzhipeng',
         father: 'wanglicai',
         mother: 'sunaiyun' },
      name: 'gino',
      sex: 'male',
      age: '27' }
    */

  • 0
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值