前端的深拷贝和浅拷贝_前端面试-深拷贝和浅拷贝

面试题目:如何实现对一个数组或对象的浅拷贝和深拷贝?

WTF,复制还分两种,第一次遇到这种问题的时候很是无语呢,先来看看一般的答案的理解。

浅拷贝是只拷贝一层,深层次的对象级别就只拷贝引用。 深拷贝是拷贝多层,每一级别的数据都拷贝出来。也就是说,基本数据类型其实不存在深浅拷贝的问题,只有对象和数组才存在深浅拷贝的问题。

主要解决的是什么问题呢?你去买房子,看中一套不错要了,然后中介给你打印了一份合同,你签字付钱。过一段时间去看,哎呀我去,怎么装修了?另外一个人也拿着同样有合同、付款凭证。我以为是我买的房子,结果中介一房两卖,别人也能搞。这怎么行?

JS数据类型

js分为基本数据类型和复杂数据类型。

基本数据类型包括:String、Number、Boolean、Null、Undefined

复杂(引用)类型包括:Object、Array、Function

在开发过程中,经常使用 typeof 来检测数据类型。默认var声明的时候,如果不进行赋值,类型就是undefined。布尔值是boolean只有 true,false两种值。

声明的时候用的null,这时候代表空对象,使用typeof检测的时候,显示是Object。

JS内存管理

JS代码运行的时候,数据都要写入内存进行调用的,而不同的数据类型在内存中存放的方式是不一样的。

基本数据类型是存储在栈数据空间中,复杂数据类型是存储在堆数据空间中的,而对数据空间不能直接访问,需要栈这边进行位置指引。

一个不是很恰当的比喻就是内存相当于仓库。

仓库里面分了两个区域,一边是都是小格子,另一边都是大货柜。简单数据类型比如你的一本书,你的一份账单什么的就直接放在小格子里面就好了。

另外你有一屋子书和一屋子的账单,小格子放不下。你就租了一个小格子和一个仓库。小格子里面放着仓库的钥匙和仓库的位置,仓库里面放东西。

实际的内存读取方式也类似。要找自己的小格子,你就要从上到下挨着找。想要找自己货柜里面的东西,还是需要先去小格子里面找到存放钥匙和位置的格子,找到以后直接去找货柜。

下图是

浅拷贝和深拷贝

再没有了解到深拷贝和浅拷贝知识的时候,一般拷贝就是从新赋值。声明个数据直接用另外一个对象赋值。这个就算是浅拷贝。

当遇到复杂对象的时候,复制的只是对象的指针,并没有重新开辟大的空间进行复制。这时候造成的影响就是对两个指针进行数据操作的时候,操作的是同一个数据内容,相互之间是受影响的。

而深拷贝就是需要连指针到内容都进行复制,两个指针指向两个空间的内容。各自操作已经不受影响。

浅拷贝的实现方式

浅拷贝的复制就是直接复制赋值就可以了。

方法一:

function simpleClone(initalObj) { var obj = {}; for ( var i in initalObj) { obj[i] = initalObj[i]; } return obj;}var obj = { b:{ a: "world", b: 21 }, c:["Bob", "Tom", "Jenny"], d:function() { alert("hello world"); }}var cloneObj = simpleClone(obj); console.log(cloneObj.b); console.log(cloneObj.c);console.log(cloneObj.d);cloneObj.b.a = "changed";cloneObj.c = [1, 2, 3];cloneObj.d = function() { alert("changed"); };console.log(obj.b);console.log(obj.c);console.log(obj.d);自行运行查看下变化及原因。

方法二: Object.assign是ES6的新函数。Object.assign() 方法可以把任意多个的源对象自身的可枚举属性拷贝给目标对象,然后返回目标对象。但是 Object.assign() 进行的是浅拷贝,拷贝的是对象的属性的引用,而不是对象本身。

Object.assign(target, ...sources)var obj = { a: {a: "hello", b: 21} };var initalObj = Object.assign({}, obj);initalObj.a.a = "changed";console.log(obj.a.a); // "changed"需要注意的是:

Object.assign()可以处理一层的深度拷贝,如下:

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 }

如果要复制的对象只有一层,对象里面的元素全是基本元素的话,前面的浅拷贝案例其实就完成了深拷贝的功能。我们重点说一下多层对象。

1.通过JSON转换 用JSON.stringify把对象转成字符串,再用JSON.parse把字符串转成新的对象。

但是这种方法也有不少坏处,譬如它会抛弃对象的constructor。也就是深拷贝之后,不管这个对象原来的构造函数是什么,在深拷贝之后都会变成Object。并且只能处理常见的Number, String, Boolean, Array, 扁平对象等这些能被JSON表示的数据结构。RegExp对象是无法通过这种方式深拷贝。

2.递归拷贝

function deepClone(initalObj, finalObj) { var obj = finalObj || {}; for (var i in initalObj) { var prop = initalObj[i]; if(prop === obj) { continue; } if (typeof prop === 'object') { obj[i] = (prop.constructor === Array) ? [] : {}; arguments.callee(prop, obj[i]); } else { obj[i] = prop; } } return obj;}递归拷贝就是将对象逐层解开进行剖析,逐层新建对象,逐层复制,知道最深处的所有简单数据都复制上。

但是要注意要注意对象引用对象的情况,会掉入死循环。

3.使用Object.create()方法 直接使用var newObj = Object.create(oldObj),可以达到深拷贝的效果。

function deepClone(initalObj, finalObj) { var obj = finalObj || {}; for (var i in initalObj) { var prop = initalObj[i]; // 避免相互引用对象导致死循环,如initalObj.a = initalObj的情况 if(prop === obj) { continue; } if (typeof prop === 'object') { obj[i] = (prop.constructor === Array) ? [] : Object.create(prop); } else { obj[i] = prop; } } return obj;}小案例

之前在进行公司VUE项目开发的过程中,由于需要将富文本编辑器抽离成为一个单独的组件,然后将内容的对象传入进去。如果按照传统的vue组件开发的流程,肯定是要接收传入、赋值给本组件、本组件编辑器修改、修改完毕的内容再进行emit外传,然后组件外部接受,进一步处理。

但是由于vue组件之间浅拷贝的特性,其实传入的对象修改之后,外部组件直接取值拿到的就是最新的值。

也是因为这个发现才对深拷贝和浅拷贝有了更加深入的了解。

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
浅拷贝是创建一个新对象,这个对象有着原始对象属性值的一份精确拷贝。如果属性是基本类型,拷贝的就是基本类型的值,如果属性是引用类型,拷贝的就是内存地址,所以如果其中一个对象改变了这个地址,就会影响到另一个对象。\[2\] 深拷贝是将一个对象从内存中完整的拷贝一份出来,从堆内存中开辟一个新的区域存放新对象,且修改新对象不会影响原对象。深拷贝会递归地复制对象中的子对象,确保所有层级的对象都被复制。\[2\] 浅拷贝的实现方式有多种,比如使用Array.concat()、Array.slice()、Object.assign()和展开运算符等。这些方法都是创建一个新的对象,但是对于引用类型的属性,仍然是共享同一块内存,所以会相互影响。\[2\] 深拷贝的实现方式也有多种,比如使用JSON.parse(JSON.stringify())和jQuery.extend()等。这些方法会递归地复制对象中的子对象,确保所有层级的对象都被复制,从而实现完全独立的拷贝。\[2\] 浅拷贝适用于对简单的对象或数组进行拷贝,当想要修改其中一个对象的值,但又要保留原来对象的值不被修改时,可以使用浅拷贝。而深拷贝适用于对复杂的对象或数组进行拷贝,当想要创建一个新的对象或数组,并且对新对象或数组的修改不会影响原对象或数组时,可以使用深拷贝。\[4\] 总结起来,浅拷贝只复制一层对象的属性,而深拷贝则递归复制了所有层级。\[2\] #### 引用[.reference_title] - *1* [有关深拷贝浅拷贝(经典前端面试题)](https://blog.csdn.net/weixin_49602426/article/details/127289749)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insert_down28v1,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* [[前端面试题]:深拷贝浅拷贝的区别](https://blog.csdn.net/WWEIZAI/article/details/126519334)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insert_down28v1,239^v3^insert_chatgpt"}} ] [.reference_item] - *3* [前端面试浅拷贝深拷贝的区别?](https://blog.csdn.net/weixin_39570751/article/details/123363926)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insert_down28v1,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值