zoukankan      html  css  js  c++  java
  • 深拷贝与浅拷贝及其实现方式

    浅拷贝:把字符串、数字的值赋值给新变量,相当于把值完全复制过去,新变量的值改变不会影响旧变量。但是对象却不同,因为是复制的地址,所以新的值改变也会影响原来的值

    var m = { a: 10, b: 20 }
    var n = m;
    n.a = 15;
    // 这时m.a的值是多少
    

    m.a会输出15,因为这是浅拷贝,n和m指向的是同一个堆,对象复制只是复制的对象的引用

    深拷贝:对象的赋值会相互影响,而数字,字符串之类的不会,我们将对象遍历,在数字、字符串将其对应赋值,这就是一般深拷贝的方式

    var m = { a: 10, b: 20 }
    var n = {a:m.a,b:m.b};
    n.a = 15;
    

    这时的m.a的值还是10,并没有改变,m对象和n对象虽然所有的值都是一样的,但在堆里面,对应的不是同一个了,这个就是深拷贝

    深拷贝的实现方式

    自己手动复制

    像上面的范例,把obj1的属性一个个复制到obj2中:

    var obj1 = { a: 10, b: 20, c: 30 };
    var obj2 = { a: obj1.a, b: obj1.b, c: obj1.c };
    obj2.b = 100;
    console.log(obj1);
    // { a: 10, b: 20, c: 30 } <-- 沒被改到
    console.log(obj2);
    // { a: 10, b: 100, c: 30 }
    

    但这样很麻烦要自己慢慢复制,而且这样其实不是 Deep Copy,如果像下面这个状况

    var obj1 = { body: { a: 10 } };
    var obj2 = { body: obj1.body };
    obj2.body.a = 20;
    console.log(obj1);
    // { body: { a: 20 } } <-- 被改到了
    console.log(obj2);
    // { body: { a: 20 } }
    console.log(obj1 === obj2);
    // false
    console.log(obj1.body === obj2.body);
    // true
    

    虽然obj1跟obj2是不同对象,但他们会共享同一个obj1.body,所以修改obj2.body.a时也会修改到旧的。

    Object.assign

    Object.assign是 ES6 的新函数,可以帮助我们达成跟上面一样的功能。

    var obj1 = { a: 10, b: 20, c: 30 };
    var obj2 = Object.assign({}, obj1);
    obj2.b = 100;
    console.log(obj1);
    // { a: 10, b: 20, c: 30 } <-- 沒被改到
    console.log(obj2);
    // { a: 10, b: 100, c: 30 }
    

    Object.assign({}, obj1)的意思是先建立一个空对象{},接着把obj1中所有的属性复制过去,所以obj2会长得跟obj1一样,这时候再修改obj2.b也不会影响obj1。

    因为Object.assign跟我们手动复制的效果相同,所以一样只能处理深度只有一层的对象,没办法做到真正的 Deep Copy。不过如果要复制的对象只有一层的话可以考虑使用它。

    转成 JSON 再转回来

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

    var obj1 = { body: { a: 10 } };
    var obj2 = JSON.parse(JSON.stringify(obj1));
    obj2.body.a = 20;
    console.log(obj1);
    // { body: { a: 10 } } <-- 沒被改到
    console.log(obj2);
    // { body: { a: 20 } }
    console.log(obj1 === obj2);
    // false
    console.log(obj1.body === obj2.body);
    // false
    

    这样做是真正的Deep Copy,但只有可以转成JSON格式的对象才可以这样用,像function没办法转成JSON。

    var obj1 = { fun: function(){ console.log(123) } };
    var obj2 = JSON.parse(JSON.stringify(obj1));
    console.log(typeof obj1.fun);
    // 'function'
    console.log(typeof obj2.fun);
    // 'undefined' <-- 没复制
    

    要复制的function会直接消失,所以这个方法只能用在单纯只有数据的对象。

    jquery

    jquery 有提供一个$.extend可以用来做 Deep Copy。

    var $ = require('jquery');
    var obj1 = {
        a: 1,
        b: { f: { g: 1 } },
        c: [1, 2, 3]
    };
    var obj2 = $.extend(true, {}, obj1);
    console.log(obj1.b.f === obj2.b.f);
    // false
    

    lodash

    另外一个很热门的函数库lodash,也有提供_.cloneDeep用来做 Deep Copy

    var _ = require('lodash');
    var obj1 = {
        a: 1,
        b: { f: { g: 1 } },
        c: [1, 2, 3]
    };
    var obj2 = _.cloneDeep(obj1);
    console.log(obj1.b.f === obj2.b.f);
    // false
    

    参考文章

    关于 JS 中的浅拷贝和深拷贝

  • 相关阅读:
    [CF1039D]You Are Given a Tree
    [洛谷P2107]小Z的AK计划
    [CF409F]000001
    [洛谷P1801]黑匣子_NOI导刊2010提高(06)
    [洛谷P3377]【模板】左偏树(可并堆)
    [洛谷P2482][SDOI2010]猪国杀
    [CF45G]Prime Problem
    [CF735D]Taxes
    [洛谷P3413]SAC#1
    [洛谷P4124][CQOI2016]手机号码
  • 原文地址:https://www.cnblogs.com/twoeggg/p/8081567.html
Copyright © 2011-2022 走看看