当前位置:首页 > 经验 >

深拷贝解决浅拷贝的问题(深拷贝的缺点)

来源:原点资讯(www.yd166.com)时间:2022-10-24 22:51:29作者:YD166手机阅读>>

深拷贝解决浅拷贝的问题,深拷贝的缺点(1)

作者:小丑

转发链接:https://mp.weixin.qq.com/s/i_vGi8C5PBa_KOV7MtVPWQ

前言

"拷贝"一直都是面试的热门考题。看似简单,实则难住不少面试者,回答的马马虎虎,模棱两可。抽出时间好好分析总结一下"拷贝",让这个难题彻底消失。

正文

从一则故事讲起,昨天因为医院开不出药,我拿上药去小区药店去买药,进门之后我问老板有没有这个药,老板转身进去一个小屋子拿了一盒药,果不其然确实有,药的名字和毫克一模一样,但是盒子的样子和厂商不一样,我问老板:“这两个药是一种药吗,盒子不一样啊,药的成分是一样的吗?”老板说当然一样啊,这个就和你去买猪肉一样,同样是猪身上的肉,只不过是你去这个超市和去其他超市买场地一样而已。最后为了安全起见,我还是没有买那个药。

"拷贝"分为浅拷贝和深拷贝。它是针对对象来说的,如果不是对象一切免谈。这里的对象可以理解为我拿的那盒药,浅拷贝可以理解为老板拿出来的那盒药,虽然药的名字和毫克一样,然后里面的我们不知道是否真的一样,可能一样可能不一样。深拷贝可以理解为我买到了一摸一样的药,一层一层的药名,毫克,厂商,成分都一样。

总结:

  • 浅拷贝就是针对对象的属性依次进行复制,只复制一层,不会递归到个属性复制,会产生引用问题即内存地址是指的同一地址。简单来说就是拷贝之后和原对象有关。
  • 深拷贝就是针对对象的各属性递归复制到新的对象上,内存地址不会指向同一地址。简单来说就是拷贝之后和原对象无关。

下面看一个浅拷贝的例子:

let school={'name':"小丑"}; let my = {age:{count:18},name:"小丑的小屋"}; let all = {...school,...my}; my.age.count=100; console.log(all); console.log(my);

结果:

{ age: { count: 100 }, name: '小丑的小屋' } { age: { count: 100 }, name: '小丑的小屋' }

结论是:浅拷贝修改拷贝之后的对象上的属性会把原对象身上的属性同时修改掉。

下面再看一个深拷贝的例子:

const _ = require("loadsh") let my = {age:{count:18},name:"小丑的小屋"}; let all = _.cloneDeep(my); all.age.count =100; console.log(my); console.log(all);

结果:

{ age: { count: 18 }, name: '小丑的小屋' } { age: { count: 100 }, name: '小丑的小屋' }

结论是:深拷贝修改拷贝之后的对象上的属性不会把原对象身上的属性同时修改掉。

拷贝的方法

1.数组方法[1]:slice和concat

  • slice

let arr = [1,2,3,4]; let arr2 = arr.slice(0) arr2[2]=5; console.log(arr); //[ 1, 2, 3, 4 ] console.log(arr2); //[ 1, 2, 5, 4 ]

当数组里是不是对象的时候从结果上看是深拷贝,再看下面例子

let arr = [{1:1,2:2}]; let arr2 = arr.slice(0) arr2[2]=5; console.log(arr); //[ { '1': 1 }, { '2': 5 } ] console.log(arr2); //[ { '1': 1 }, { '2': 5 } ]

当数组里是对象的时候就变成了浅拷贝

  • concat

let arr = [1,2,3,4]; let arr2 = [].concat(arr); arr2[2]=5; console.log(arr); //[ 1, 2, 3, 4 ] ✔ console.log(arr2); //[ 1, 2, 5, 4 ]

当数组里不是对象的时候从结果上看是深拷贝,再看下面例子

let arr = [{1:1},{2:2}]; let arr2 = arr.cancat(0) arr2[1][2]=5; console.log(arr); //[ { '1': 1 }, { '2': 5 } ] ❌变成了引用 console.log(arr2); //[ { '1': 1 }, { '2': 5 } ]

当数组里是对象的时候就变成了浅拷贝

总结:只有当数组是一维数组而且不包含对象的时候才是深拷贝

2.Object.assgin()

let a= {a:1,b:2}; let b= Object.assign({},a); a.a=3; console.log(a) //{a: 3, b: 2} console.log(b) //{a: 1, b: 2} ✔

let a= {a:1,b:{c:2}}; let b= Object.assign({},a); a.b.c=3; console.log(a) //{a: 1, b: {c:3}} console.log(b) //{a: 1, b: {c:3}} ❌变成了引用

总结:Object.assgin如果涉及到嵌套多个对象的话就变成了引用 解决方法:使用JSON.stringify()先转化成字符串,再通过JSON.parse()转化成对象

  • 3.JSON.parse(JSON.stringify())

let a= {a:1,b:{c:2}}; let b= JSON.parse(JSON.stringify(a)) a.b.c=3; console.log(a) //{a: 1, b: {c:3}} console.log(b) //{a: 1, b: {c:2}} ✔

let school={'name':"小丑的小屋",fn:function(){}}; let my = {age:{count:18},name:"小丑的小屋"}; let all=JSON.parse(JSON.stringify({...school,...my})) console.log(all); //{'name':"小丑的小屋",age:{count:18}}; //❌把fn给丢了

总结:JSON.parse(JSON.stringify())这个方法有一定的局限性,会丢失fn。

  • 4.手写深拷贝

let deepClone=(obj)=>{ if(obj==undefined) return obj; //undefined == null if(obj instanceof RegExp) return new RegExp(obj); if(obj instanceof Date) return new Date(obj); if(typeof obj!=="object") return obj; let newObj = new obj.constructor; for(let key in obj){ if(obj.hasOwnProperty(key)){ newObj[key] = deepClone(obj[key]) } } return newObj; }

let obj1 = {name:{age:"10"}} let n = deepClone(obj1) obj1.name.age = "231" console.log(n); //{name:{age:"10"}} ✔

let obj = { name:"小丑的小屋" } obj.aaa=obj let n = deepClone(obj1) console.log(n); //死循环了 ❌

解决这个问题可以使用WeakMap[2]

let deepClone=(obj,hash=new WeakMap())=>{ if(obj==undefined) return obj; //undefined == null if(obj instanceof RegExp) return new RegExp(obj); if(obj instanceof Date) return new Date(obj); if(typeof obj!=="object") return obj; if(hash.has(obj)) return hash.get(obj); let newObj = new obj.constructor; hash.set(obj,newObj); for(let key in obj){ if(obj.hasOwnProperty(key)){ newObj[key] = deepClone(obj[key],hash) } } return newObj; }

  • 5.lodash的cloneDeep

源码地址:https://github.com/lodash/lodash/blob/86a852fe763935bb64c12589df5391fd7d3bb14d/.internal/baseClone.js

  • 6.vue-router源码中的克隆方法

function clone (value) { if (Array.isArray(value)) { return value.map(clone) } else if (value && typeof value === 'object') { const res = {} for (const key in value) { res[key] = clone(value[key]) } return res } else { return value } }

let arr = [{1:1},{2:2},function(){}]; let arr2 = clone(arr) arr2[1][2]=5; console.log(arr) //[ { '1': 1 }, { '2': 2 }, [Function (anonymous)] ] ✔ 深拷贝 console.log(arr2); //[ { '1': 1 }, { '2': 5 }, [Function (anonymous)] ]

function extend (a, b) { for (const key in b) { a[key] = b[key] } return a }

let b={a:1,b:{c:2}}; let a= extend({},b); a.b.c=5; console.log(a); //{ a: 1, b: { c: 5 } } console.log(b); //{ a: 1, b: { c: 5 } } 浅拷贝

作者:小丑

转发链接:https://mp.weixin.qq.com/s/i_vGi8C5PBa_KOV7MtVPWQ

栏目热文

浅拷贝和深拷贝的值会不会变(高拷贝和低拷贝的区别)

浅拷贝和深拷贝的值会不会变(高拷贝和低拷贝的区别)

前面我们曾经聊到列表从内存的角度是什么样的?有兴趣的可以关注我,看一下《python之从内存读写的角度,学习并玩转lis...

2022-10-24 22:44:50查看全文 >>

为什么要深拷贝浅拷贝(零拷贝和深拷贝)

为什么要深拷贝浅拷贝(零拷贝和深拷贝)

关于对象的拷贝,大部分时间我们用的都是浅拷贝,比如赋值符号(“=”)以及memcpy()等。那么既然浅拷贝这么简单,为...

2022-10-24 22:08:28查看全文 >>

深拷贝和浅拷贝和零拷贝的区别(深拷贝与浅拷贝示意图)

深拷贝和浅拷贝和零拷贝的区别(深拷贝与浅拷贝示意图)

原型模式也是创建对象的一种方式,它一般用在这样的场景:系统中存在大量相同或相似对象的创建问题,如果用传统的构造函数来创建...

2022-10-24 22:15:15查看全文 >>

深拷贝和浅拷贝的方法(深拷贝的方法及优缺点)

深拷贝和浅拷贝的方法(深拷贝的方法及优缺点)

由于JavaScript中对象是引用类型,保存的是地址,深、浅拷贝的区别是,当拷贝结束后,在一定程度上改变原对象中的某一...

2022-10-24 22:44:42查看全文 >>

白糖和化肥为什么能爆炸(国家为什么要管控白糖)

白糖和化肥为什么能爆炸(国家为什么要管控白糖)

【军武次位面】作者:leon最近,克里米亚大桥被炸毁的消息想必是引起了全球的关注与报道,作为当前俄乌冲突中的极具战略价值...

2022-10-24 22:10:34查看全文 >>

深拷贝和浅拷贝的简单理解(深拷贝解决浅拷贝的问题)

深拷贝和浅拷贝的简单理解(深拷贝解决浅拷贝的问题)

前言平时我们从数据库查询出 po 对象,要返回给前端时,会有另一个对象 vo,此时我们需要将 po 的值复制给 vo,如...

2022-10-24 22:07:09查看全文 >>

简述浅拷贝和深拷贝的区别(浅拷贝深拷贝哪个是原地操作)

简述浅拷贝和深拷贝的区别(浅拷贝深拷贝哪个是原地操作)

使用场景:开发的时候对引用类型进行处理,为了避免修改一个引用类型数据时,其他用这个变量来赋值的变量也都被改变了。如下例子...

2022-10-24 22:53:14查看全文 >>

深拷贝和浅拷贝图解(深拷贝和浅拷贝的方法)

深拷贝和浅拷贝图解(深拷贝和浅拷贝的方法)

作者:南枝向暖北枝寒MA 原文链接:https://blog.csdn.net/mall_lucy/article/de...

2022-10-24 22:21:57查看全文 >>

谈谈你对浅拷贝和深拷贝的理解(零拷贝和深拷贝)

谈谈你对浅拷贝和深拷贝的理解(零拷贝和深拷贝)

先说下自己的理解吧,浅拷贝,即在定义一个类A,使用类似A obj; A obj1(obj);或者A obj1 = obj...

2022-10-24 22:24:54查看全文 >>

深拷贝和浅拷贝有哪些应用

深拷贝和浅拷贝有哪些应用

大家好我是发哥,本期说说C 深拷贝和浅拷贝。对于基本类型的数据以及简单的对象,它们之间的拷贝非常简单,就是按位复制内存...

2022-10-24 22:41:01查看全文 >>

文档排行