首页 > 其他分享 >从来都没有理解浅拷贝与深拷贝?我非把你教会不可!最全的深拷贝方案,绝对全!!看这一篇就够了大白话!

从来都没有理解浅拷贝与深拷贝?我非把你教会不可!最全的深拷贝方案,绝对全!!看这一篇就够了大白话!

时间:2023-05-07 22:00:55浏览次数:37  
标签:obj2 obj 大白话 数据类型 就够 var console 拷贝

首先,想真正理解深浅拷贝,需要清楚地知道堆和栈,那么你知道简单数据类型和引用数据类型在堆和栈的关系吗?

栈:基本数据类型的值,引用数据类型的地址。

堆:引用数据类型的值。

我画个图,便于你理解。堆空间远远大于栈空间,可以发现,当数据类型为简单数据类型时,它的值和地址都在堆中,所以一般对于深拷贝浅拷贝都相对于引用数据类型来说的,如果严格区分基本类型的复制,也可以说属于深拷贝。所以,可以说无论哪种数据类型,存储其值所声明的变量都存在于栈空间!

从来都没有理解浅拷贝与深拷贝?我非把你教会不可!最全的深拷贝方案,绝对全!!看这一篇就够了大白话!_循环引用

引用数据类型在使用“=”时,赋值的是栈空间中的地址。

注意:尽量避免使用“=”对引用数据类型进行拷贝;修改一个对象,也会影响另一个对象。

浅拷贝:对于对象和数组引用数据类型赋值时,只是把地址复制过去,一个值变化也会影响另一个值变化。(看下面图片再来看看这句话哦!!)

上例子:var obj = {

            uname: "张三",

            age: "18"

  }

  var obj2 = obj;

        obj2.uname = "李四"

        console.log("obj:", obj);

        console.log("obj2:", obj2);

从来都没有理解浅拷贝与深拷贝?我非把你教会不可!最全的深拷贝方案,绝对全!!看这一篇就够了大白话!_深拷贝_02

深拷贝:对于对象和数组引用数据类型赋值时,如果我们把值赋过去(产生了一个新的值),此时,不影响另一个值变化

上例子:var obj = {

            uname: "张三",

            age: "18",

            address: "北京",

            aiHao: ["吃", "喝"],

            car: {

            }

        }

var obj2 = {};

        for (var key in obj) {

            console.log("key:", key); // 属性名

            console.log(obj[key]); // 属性值

            // 对象[属性名] = 属性值

            obj2[key] = obj[key]

            // obj2['aiHao'] = ["吃", "喝"]

        }

        obj.age = 20

        obj.aiHao.push("玩")

        console.log("obj:", obj);

        console.log("obj2:", obj2);

这里我用了for...in 通过遍历对象并声明obj2(空对象)来盛装对象中每一个属性,先别急,我知道还有其他方法,我后面会做总结喔!!!这里只是抛砖引玉,你会发现上面例子只能实现含有一层引用数据类型的对象,那么对象里面可能还有多层嵌套(对象中还有包含多个数组/对象的数组/对象),又该怎么办呢?

上例子: var obj = {

            uname: "张三",

            age: "18",

            address: "北京",

            aiHao: ["吃", "喝", []],

            car: {

                jiaGe: "100",

                pinPai: "bmw"

            },

             say: function () { }

        }    

var objStr = JSON.stringify(obj)

        var obj2Str = objStr

        var obj2 = JSON.parse(obj2Str);

        obj.uname = "李四";

        obj.aiHao.push("玩");

        console.log("obj:", obj);

        console.log("obj2:", obj2);   //fn被忽略

这里是通过json方法实现的深拷贝,

但是!!!有两种情况会出现bug:第一种情况,使用json方法实现深拷贝不能拷贝函数,因为当拷贝的数据中有函数类型,会自动忽略,打印时候发现根本没有拷贝到fn;第二种情况如下,牵扯到循环引用(什么是循环引用,我在下面打印一下,你就知道了)

从来都没有理解浅拷贝与深拷贝?我非把你教会不可!最全的深拷贝方案,绝对全!!看这一篇就够了大白话!_引用数据类型_03

从来都没有理解浅拷贝与深拷贝?我非把你教会不可!最全的深拷贝方案,绝对全!!看这一篇就够了大白话!_循环引用_04

下面是循环引用的样子:

从来都没有理解浅拷贝与深拷贝?我非把你教会不可!最全的深拷贝方案,绝对全!!看这一篇就够了大白话!_循环引用_05

从来都没有理解浅拷贝与深拷贝?我非把你教会不可!最全的深拷贝方案,绝对全!!看这一篇就够了大白话!_深拷贝_06

那么有没有很完美的深拷贝呢,我先写一种自己封装的深拷贝函数,这种比较好理解,后面还有另一种,往下找哦!!!:

从来都没有理解浅拷贝与深拷贝?我非把你教会不可!最全的深拷贝方案,绝对全!!看这一篇就够了大白话!_引用数据类型_07

最后,我来总结一下我自己总结的全部的深拷贝方案以及优缺点:

第一种:

深拷贝的第一种方案(展开运算符实现) 特点:能实现一层拷贝,如果有多层,实现不了。

从来都没有理解浅拷贝与深拷贝?我非把你教会不可!最全的深拷贝方案,绝对全!!看这一篇就够了大白话!_循环引用_08

第二种:

深拷贝的第二种方案(上面我提到的json实现) ,能实现多层拷贝,如果对象中有方法,会把对象中的方法丢掉,而且不能实现循环引用,会报错,详细见上文哦!!!。

从来都没有理解浅拷贝与深拷贝?我非把你教会不可!最全的深拷贝方案,绝对全!!看这一篇就够了大白话!_循环引用_09

第三种(不正规):

深拷贝的第三种方案(通过原型实现的),表现像深拷贝,从内存的角度分析是原型实现,深层次的也实现不了。但是效果确实实现了。

从来都没有理解浅拷贝与深拷贝?我非把你教会不可!最全的深拷贝方案,绝对全!!看这一篇就够了大白话!_引用数据类型_10

第四种:

自己手写封装深拷贝(看上图,有详细解释哦!!!)

第五种:

使用第三方的库lodash(可以去官网找)实现

从来都没有理解浅拷贝与深拷贝?我非把你教会不可!最全的深拷贝方案,绝对全!!看这一篇就够了大白话!_引用数据类型_11

 第六种:

这个也是自己封装的,但是比上面一种简练,方法不一样。

function shen(a) {

            var x = a instanceof Array ? [] : {}

            for (var i in a) {

                x[i] = a[i] instanceof Object ? arguments.callee(a[i]) : a[i]

            }

            return x

        }

        var obj3 = shen(obj)

        obj3.name = "赵六"

        obj3.data.msg = '失败'

        console.log('obj3:', obj3);  // 深拷贝,完美复刻,任意修改,完全不影响原数据

第七种:

这种牵扯到底层原理,小伙伴们研究看看哦!!!

 function structuralClone(obj) {

            return new Promise(resolve => {

                const { port1, port2 } = new MessageChannel()

                port1.postMessage(obj)

                port2.onmessage = e => resolve(e.data)  // e是MessageChannel构造函数本身

            })

        }

        obj.data.d = obj.data

        // 注意该方法是异步的 // 可以处理 undefined 和循环引用对象

        const test = async () => {

            const obj5 = await structuralClone(obj)

            console.log('obj5',obj5)

        }

        test() 

整理不易,望小伙伴们多多指教!!!


标签:obj2,obj,大白话,数据类型,就够,var,console,拷贝
From: https://blog.51cto.com/u_16090498/6252624

相关文章

  • 【C#】数组深拷贝
    数组是引用类型,元素保存在堆上,栈上保存的是地址。1.Buffer.BlockCopyint[]arrold=newint[100000];int[]arrnew=newint[100000];//foreach不能修改遍历集合的元素内容for(inti=0;i<arrold.Length;++i){arrold[i]=i;}Stopwatchsw=newStopwatch(......
  • ChatGPT最全提示词Prompts总结,看这一篇就够了!
    以下几乎涵盖了各类人群想要使用ChatGPT的所有提示词,需要的朋友可以直接复制粘贴使用。从翻译到整理耗费超过2个小时,如果内容对大家有帮助,请不要吝啬你们的喜欢、点赞、关注~​如何正确的提问?担任创业技术律师我将要求您准备一页纸的设计合作伙伴协议草案,该协议是一家拥有I......
  • linux 写时拷贝技术
    写时拷贝就是等到修改数据时才真正分配内存空间,这是对程序性能的优化,可以延迟甚至是避免内存拷贝,当然目的就是避免不必要的内存拷贝。比如说,我们建立两个进程每一个都存在一个值为10的变量,操作系统并不会通过页表映射两块物理内存,而是只开辟一块物理内存,同时让两个进程的不同虚拟......
  • Linq大白话深入浅出从零基础到手写开源工具兵贵神速系列(一)——为啥需要Linq
    所有的技术创新都是为了解决编程实践中的难点和痛点!如果我们不懂得这项技术所要解决的难点和痛点,我们在使用这项技术的时候就很可能走偏,在细节末节上隔靴搔痒,耗费很长的时间还掌握不了这项技术的精髓!而很多道友虽然在项目中掌握了一些基本的用法但是知其然而不知其所以然,不知道......
  • Linux下用tar完整拷贝/备份目录
    保留软连接、createtime、accesstime、modifytime、permission信息以拷贝/mnt/myhome/username到/mnt/newhome/username为例:cd/mnt/myhometar-cf-username|(cd/mnt/newhome&&tar-xpf-)管道符前的tar将文件夹username打包为tar归档文件,并将其输出到......
  • 赋值/浅拷贝/深度拷贝
     /*一:赋值二:浅拷贝二:深拷贝*/ 一:赋值#赋值if__name__=='__main__':dict1={'user':'Tom','num':[1,2,3]}#直接赋值:引用对象dict2=dict1print("dict1:0x%x"%id(dict1),dict2)#di......
  • 一文彻底搞懂ZAB算法,看这篇就够了!!!
    最近需要设计一个分布式系统,需要一个中间件来存储共享的信息,来保证多个系统之间的数据一致性,调研了两个主流框架Zookeeper和ETCD,发现都能满足我们的系统需求。其中ETCD是K8s中采用的分布式存储,而其底层采用了RAFT算法来保证一致性,之前已经详细分析了Raft算法的原理,今天主要仔细分......
  • js封装深拷贝方法
    deepCopy:function(data){ if(data===null||data===undefined){ returnnull; } letresult=Array.isArray(data)?[]:{}; if(data&&typeofdata==='object'){ for(letkeyindata){ if(data[key]&&typeof......
  • 将字节数组输入流拷贝成字节数组输出流,将ByteArrayInputStream转成ByteArrayOutputStr
    /**将ByteArrayInputStream拷贝成ByteArrayOutputStream*将字节数组输入流拷贝成字节数组输出流*/publicstaticByteArrayOutputStreamgetByteArrayOutputStream(ByteArrayInputStreaminputStream)throwsIOException{ByteArrayOutpu......
  • 列表拷贝
    1.lst2=lst1#都将指向同一个列表对象,有相同的id此时,在lst1中所做的修改将反映在lst2中,反之亦然。 2.也可以使用copy()函数来复制python列表lst2=lst1.copy()#指向内存中不同的列表对象 3.lst2=copy(lst1)#指向内存中不同的列表对象 4.列表生成......