• JS的深浅复制,原来如此!


    摘要:之所以会出现深浅拷贝的问题,实质上是由于JS对基本类型和引用类型的处理不同。

    本文分享自华为云社区《js的深浅复制,一看就明白》,作者: 鑫2020。

    浅复制的意思

    浅复制是仅仅对数据存放在栈内的引用的复制,没有复制引用指向堆内的内容。多个数据的浅复制,这复制多个引用,这多个引用共同指向堆内的同一个内容。当一个浅复制数据做出修改,即堆内的引用指向的内容发生修改,这时,其他通过引用指向这里的数据也会随着改变。

    let obj = {
        a:1,
        b:2,
        c:{
            c1:10,
            c2:20
        }
    }
    
    let objA = obj;
    objA.a = 'a';
    
    console.log(obj.a);  // 'a'
    console.log(objA.a);  // 'a'

    深复制的意思

    深复制是指连同堆的内容一块复制,生成一个新的对象。多个深复制将是多个不同的对象,也就有不同的引用,也就指向不同的堆内容。

    使用深复制的原由

    在平常开发中,有时会有数据的传递与接收,当拿到传过来的数据后,难免需要对数据进行加工和改造,为了不破坏原有数据结构,这时就可以使用深复制拷贝数据,然后处理生成的新的数据。深复制也可以防止修改多个引用后引用混乱的问题,减少BUG的产生机会。

    可实现深复制的几种方法

    实现方式一:JSON的序列化与反序列化

    let obj = {
        a:1,
        b:2,
        c:{
            c1:10,
            c2:20
        }
    }
    
    let objA = JSON.parse(JSON.stringify(obj));//JSON的序列化与反序列化
    objA.a = 'a';
    
    console.log(obj.a);  // 1
    console.log(objA.a);  // 'a'

    虽然JSON的序列化与反序列化可以实现深复制,但有几个缺点需要注意:
    1、date日期对象被转成日期日期字符串
    2、没法访问到原型
    3、复制不了undefined的属性
    4、NAN和无穷被转为NULL

    let d1 = new Date();
    let obj = {
        d1,
        d2: undefined,
        d3:NaN
    }
    let objD = JSON.parse(JSON.stringify(obj));
    console.log(obj) 
    console.log(objD)

    实现方式二:Object.assign()

    let obj = {
        a:1,
        b:2,
        c:{
            c1:10,
            c2:20
        }
    }
    
    let objA = Object.assign(obj);
    objA.a = 'a';
    
    console.log(obj.a);  // 1
    console.log(objA.a);  // 'a'

    虽然Object.assign()可以实现深复制,但对于更深层次的对象引用也是仅仅浅复制。

    let obj = {
        a:1,
        b:2,
        c:{
            c1:10,
            c2:20
        }
    }
    
    let objA = Object.assign(obj);
    objA.c.c1 = 'c1'; //Object.assign()仅仅是一层深复制。
    
    console.log(obj.c.c1);  // 'c1'
    console.log(objA.c.c1);  // 'c1'

    实现方式三:扩展运算符

    let obj = {
        a:1,
        b:2,
        c:{
            c1:10,
            c2:20
        }
    }
    
    let objA = {...obj};;
    objA.a = 'a';
    
    console.log(obj.a);  // 1
    console.log(objA.a);  // 'a'

    虽然扩展运算符"…"可以实现深复制,但对于更深层次的对象引用也是仅仅浅复制。

    let obj = {
        a:1,
        b:2,
        c:{
            c1:10,
            c2:20
        }
    }
    
    let objA = {...obj};
    objA.c.c1 = 'c1'; //扩展运算符"..."同Object.assign()一样,仅仅是一层深复制,不能多层深复制。
    
    console.log(obj.c.c1);  // 'c1'
    console.log(objA.c.c1);  // 'c1'

    实现方式四:使用递归

    想要实现深复制,且实现多层深复制则可以使用递归循环复制。

    let obj = {
        a:1,
        b:2,
        c:{
            c1:10,
            c2:20
        }
    }
    
    const ReCopy = function (paramter) {
            let target = null;
            let isObject = paramter.constructor === Object;
            let isArray = paramter.constructor === Array;
            if (isObject || isArray) {
                target = Array.isArray(paramter) ? [] : {};
                for (let i in paramter) {
                    target[i] = ReCopy(paramter[i]);
                }
            } else {
                target = paramter;
            }
            return target;
        }
    
    let objA = ReCopy(obj);
    objA.c.c1 = 'c1';
    
    console.log(obj.c.c1);  // 10
    console.log(objA.c.c1);  // 'c1'

    ladash深拷贝

    lodash深复制是更专业的深复制方式。

    • 安装lodash
      先初始化,生成package.json文件,然后使用一下命令安装。
    npm i -S lodash
    • 引入lodash
    var _ = require('lodash');
    • 使用lodash
    let obj = {
        a:1,
        b:2,
        c:{
            c1:10,
            c2:20
        }
    }
    
    let objA = _.cloneDeep(obj);
    objA.c.c1 = 'c1'; 
    
    console.log(obj.c.c1);  // 10
    console.log(objA.c.c1);  // 'c1'

     

    点击关注,第一时间了解华为云新鲜技术~

  • 相关阅读:
    LRT最大似然比检验
    EPNP理论分析
    奇异值SVD分解
    矩阵求导
    static_cast和dynamic_cast用法
    Django 使用 Celery 实现异步任务
    python爬虫实战一:分析豆瓣中最新电影的影评
    scrapy模拟登陆知乎--抓取热点话题
    一个小时搭建一个全栈Web应用框架(上)
    一个小时搭建一个全栈 Web 应用框架(下)——美化与功能
  • 原文地址:https://www.cnblogs.com/huaweiyun/p/15402158.html
Copyright © 2020-2023  润新知