【面试题】马上金九银十了,简历该准备起来了,面试题你准备好了吗 ?浅谈 JS 浅拷贝和深拷贝

代码展示

let obj_old = {name: 'Tom',age: 15,favorite: {food: 'bread',drink: 'milk'}
}
let obj_new = {...obj_old}
console.log(obj_old === obj_new)  // false
console.log(obj_old.name === obj_new.name)  // true
console.log(obj_old.favorite === obj_new.favorite)  // true

3. Array.prototype.concat()

语法:arr.concat(value0, /* … ,*/ valueN)

注:如果省略了所有 valueN 参数,则 concat 会返回调用此方法的现存数组的一个浅拷贝。

代码展示

let arr_old = [1, 2, {name: 'Tom'}]
let arr_new = arr_old.concat()
console.log(arr_old === arr_new)  // false
console.log(arr_old.name === arr_new.name)  // true

4. Array.prototype.slice()

语法:arr.slice(begin, end)

注:如果省略了 beginend 参数,则 slice 会返回调用此方法的现存数组的一个浅拷贝。

代码展示

let arr_old = [1, 2, {name: 'Tom'}]
let arr_new = arr_old.slice()
console.log(arr_old === arr_new)  // false
console.log(arr_old.name === arr_new.name)  // true

🌄深拷贝

接下来说深拷贝

深拷贝就是在堆内存中开辟一个新的空间存放新对象,拷贝原对象的所有属性,拷贝前后两个对象互不影响

深拷贝的新旧对象不共享内存

这时我们去修改新对象中的任意层级的任意属性值,都不会对原对象产生影响,原对象依然保持不变

举个栗子🌰

let obj_old = {name: 'Tom',age: 15,hobby: ['eat', 'game'],favorite: {food: 'bread',drink: {dname: 'milk',color: 'white',},}
}
let obj_new = _.cloneDeep(obj_old)
console.log(obj_old)
console.log(obj_new)
console.log(obj_old.name === obj_new.name)
console.log(obj_old.favorite === obj_new.favorite)
console.log(obj_old.favorite.drink === obj_new.favorite.drink)

这里我们使用了lodash工具库提供的_.cloneDeep深拷贝方法,来看一下新旧对象的对比

可以看见新旧对象所有属性及属性值完全相同

那再来细节对比一下,看看拷贝后对象的地址是否相同

obj_old.name === obj_new.name为true,这个是基本数据类型,完全相同,没有问题

obj_old.favorite === obj_new.favorite,这里为false,到这里就和浅拷贝不同了,浅拷贝到这一层的时候,对象属性的地址是相同的,而深拷贝是完全拷贝出一个新的对象,所以不管是哪一层,对象属性的地址都是不同的

obj_old.favorite.drink === obj_new.favorite.drink为false,再往深一层仍然是false,即地址不相同

那再来修改一下属性值,看看前后对比

obj_new.name = 'Jerry'
obj_new.hobby[0] = 'sing'
obj_new.favorite.food = 'cheese'

修改属性值之后,新旧对象是互不影响的

🏷️深拷贝的方法

那么现在就来罗列几个深拷贝的方法

1. 递归实现

使用递归实现原对象每一层的拷贝,当遇到基本数据类型时,直接拷贝,遇到引用数据类型时,递归拷贝它的每个属性

代码展示

const obj_old = {name: 'Tom',age: 15,hobby: ['eat', 'game'],favorite: {food: 'bread',drink: {dname: 'milk',color: 'white',},}
}
const obj_new = {}function deepClone(newObj, oldObj){for (const key in oldObj) {if (oldObj[key] instanceof Object) {newObj[key] = {}deepClone(newObj[key], oldObj[key])} else if (oldObj[key] instanceof Array) {newObj[key] = []deepClone(newObj[key], oldObj[key])} else {newObj[key] = oldObj[key]}}
}deepClone(obj_new, obj_old)console.log(obj_old)
console.log(obj_new)
console.log(obj_old.name === obj_new.name)
console.log(obj_old.favorite === obj_new.favorite)
console.log(obj_old.favorite.drink === obj_new.favorite.drink)

测试结果

2. lodash工具包

点这里去lodash的中文文档

引入成功后,我们直接使用lodash提供给我们的函数_.cloneDeep就行

代码展示

let obj_old = {name: 'Tom',age: 15,hobby: ['eat', 'game'],favorite: {food: 'bread',drink: {dname: 'milk',color: 'white',},}
}
let obj_new = _.cloneDeep(obj_old)console.log(obj_old)
console.log(obj_new)
console.log(obj_old.name === obj_new.name)
console.log(obj_old.favorite === obj_new.favorite)
console.log(obj_old.favorite.drink === obj_new.favorite.drink)

测试结果

3. JSON.parse(JSON.stringify(obj))

JSON.stringify() 将JSON格式的对象转为字符串

JSON.parse() 将JSON格式的字符串转为对象

代码展示

const obj_old = {name: 'Tom',age: 15,hobby: ['eat', 'game'],favorite: {food: 'bread',drink: {dname: 'milk',color: 'white',},}
}
const obj_new = JSON.parse(JSON.stringify(obj_old))console.log(obj_old)
console.log(obj_new)
console.log(obj_old.name === obj_new.name)
console.log(obj_old.favorite === obj_new.favorite)
console.log(obj_old.favorite.drink === obj_new.favorite.drink)

测试结果

❣️虽然这个方法最简单,代码行数最少,但是它也有一定的缺陷:

  1. 拷贝对象的值中如果有‘函数’,‘undefined’,‘symbol’ JSON.stringify()序列化后,键值对丢失
  2. 拷贝RegExp会变成空对象{}
  3. 对象中含有‘NaN’,‘Infinity’会变成null
  4. 拷贝Date会变成字符串

🏝️结语

其实前端开发的知识点就那么多,面试问来问去还是那么点东西。所以面试没有其他的诀窍,只看你对这些知识点准备的充分程度。so,出去面试时先看看自己复习到了哪个阶段就好。

这里再分享一个复习的路线:(以下体系的复习资料是我从各路大佬收集整理好的)

《前端开发四大模块核心知识笔记》

最后,说个题外话,我在一线互联网企业工作十余年里,指导过不少同行后辈。帮助很多人得到了学习和成长。

我意识到有很多经验和知识值得分享给大家,也可以通过我们的能力和经验解答大家在IT学习中的很多困惑,所以在工作繁忙的情况下还是坚持各种整理和分享。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/359713.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

视频云存储平台LntonCVS国标视频平台功能和应用场景详细介绍

LntonCVS国标视频融合云平台基于先进的端-边-云一体化架构设计,以轻便的部署和灵活多样的功能为特点。该平台不仅支持多种通信协议如GB28181、RTSP、Onvif、海康SDK、Ehome、大华SDK、RTMP推流等,还能兼容各类设备,包括IPC、NVR和监控平台。在…

网站制作和推广

在当今数字化时代,拥有一个网站对于企业的发展和推广来说是至关重要的。网站既可以作为一个企业的形象展示,也可以作为一个销售渠道,更可以作为一个品牌传播的平台。在本文中,我们将讨论网站制作和推广的重要性,以及一…

为什么要学习PMP

学习PMP(项目管理专业人士认证)能够在职场竞争力、薪资待遇、项目管理技能等方面带来显著的提升。以下是学习PMP的具体分析: 1、职场竞争力 升职加薪:学习PMP能够提升个人在项目中的管理能力和解决问题的能力,从而在…

渗透测试基础(六) MS10-046漏洞攻击

1. 漏洞介绍 1.1 漏洞介绍 Microsoft Windows快捷方式LNK文件自动执行代码漏洞。Windows支持使用快捷方式或LNK文件。LNK文件是指向本地文件的引用,点击LNK文件与点击快捷方式所制定的目标具有相同效果。Windows没有正确的处理LNK文件,特制的LNK文件可能导致Windows自动执行…

【Leetcode每日一题】 01背包 - DP41 【模板】01背包(难度⭐⭐)(80)

1. 题目解析 题目链接:DP41 【模板】01背包 这个问题的理解其实相当简单,只需看一下示例,基本就能明白其含义了。 2.算法原理 第一问:不超过总体积的背包问题 1. 状态表示 dp[i][j] 表示:从前 i 个物品中挑选&…

MOE学习笔记

MOE网络结构 和传统的 transformer 网络结构相比,我们将 Transformer 模型的每个 FFN 层替换为 MoE 层,MoE 层由门网络(Router)和一定数量的专家(Expert)组成。 这些 Expert 其实也是 FFN 层,…

探秘神经网络激活函数:Sigmoid、Tanh和ReLU,解析非线性激活函数的神奇之处

引言 在神经网络中,激活函数扮演着至关重要的角色。它们赋予神经网络非线性的能力,使得网络具备学习和表示复杂函数关系的能力。本文将详细解析三种常见的激活函数:Sigmoid、Tanh和ReLU,揭开它们在神经网络中的奥秘。无论你是初学…

5. Revit API: Application

5. Revit API: Application 前言 上一篇中,讲到了UI篇的Ribbon(界面),并提到要创建 RibbonPanel,需要使用UIControlledApplication.CreateRibbonPanel(..)方法,还在结尾说到要写“UI”开头的那些个类&…

算法社区-从零开始构建(一)

好久没动笔了,一是要处理的东西很多,二则写出来未见得深刻,感觉沉淀得不够,太浅显的东西就没必要分享。 正好最近在研究算法层面的东西,感觉挺受用的,就想着把这些东西整理出来,有点像社区的雏形…

【例子】webpack配合babel实现 es6 语法转 es5 案例 [通俗易懂]

首先来说一下实现 es6 转 es5 的一个简单步骤 1、新建一个项目,并且在命令行中初始化项目 npm init -y2、安装对应版本的 webpack webpack-cli(命令行工具) "webpack""webpack-cli"3、安装 Babel 核心库和相关的 loader "babel-core&qu…

新质生产力潮水里:谁在为中小企业搭起一座桥?

与其说华为云为中小企业提供的是一个个更具性价比和产业适配度的产品,更本质来看,其通过618营销季为中小企业提供了一个数字化转型升级的契机,基于此,企业可以在云计算和AI时代实现内在变革,焕发新的生机与活力。 作者…

针对AIGC检测的鲁棒性测试——常见攻击手段汇总

前言:这篇文章来总结一下针对AIGC检测的常见攻击手段,选取的研究工作均出自近5年AIGC检测相关文章。(论文被拒了需要补实验,先来看看别人怎么做的……) 2019 WIFS Detecting and Simulating Artifacts in GAN Fake Ima…

泛微E9开发 根据判断条件,控制字段的编辑/必填属性

根据判断条件,控制字段的编辑/必填属性 1、需求说明2、实现方法3、扩展知识点1. 注册钩子事件,指定动作完成后触发1.1 接口名称及参数说明1.2 案例 2. 改变单个字段显示属性(只读/必填等)2.1 参数说明2.2 案例 1、需求说明 当字段“填报人”和字段“姓名…

vue3中ref标签

<tempalce><aa refa/> </tempalce> <script setup> import {ref} from vue //需要先定义一个空的ref let a ref() //然后才能使用组件ref的标签数据 </script> 然后需要在该组件中暴露出去 defineExpose({a,b,c})

ONLYOFFICE 桌面编辑器 8.1重磅来袭:全新功能提升您的办公效率

文章目录 前言ONLYOFFICE 桌面编辑器8.1一、PDF编辑&#xff1a;告别“头痛”时刻二、幻灯片版式&#xff1a;秒变“设计大师”三、无缝切换&#xff1a;办公界的“快速通道”四、语言支持&#xff1a;全球通吃的“翻译官”五、 隐藏“连接到云”板块&#xff1a;摆脱“云”的束…

Java NIO Buffer概念

针对每一种基本类型的 Buffer &#xff0c;NIO 又根据 Buffer 背后的数据存储内存不同分为了&#xff1a;HeapBuffer&#xff0c;DirectBuffer&#xff0c;MappedBuffer。 HeapBuffer 顾名思义它背后的存储内存是在 JVM 堆中分配&#xff0c;在堆中分配一个数组用来存放 Buffe…

73. UE5 RPG 优化投射物以及敌人生成

解决发射物会与地面产生交互的问题 之前一直遇到发射物的体积过大会在发射时&#xff0c;和地面产生交互&#xff0c;我们可以调整小一些&#xff0c;然后为了防止它和自身产生交互事件。我们可以实现它在生成后&#xff0c;不会触发相关事件&#xff0c;而是在一定时间后。 对…

k8s如何使用 HPA 实现自动扩展

使用Horizontal Pod Autoscaler (HPA) 实验目标&#xff1a; 学习如何使用 HPA 实现自动扩展。 实验步骤&#xff1a; 创建一个 Deployment&#xff0c;并设置 CPU 或内存的资源请求。创建一个 HPA&#xff0c;设置扩展策略。生成负载&#xff0c;观察 HPA 如何自动扩展 Pod…

Arduino称重传感器和 HX711 放大器(数字秤)

Arduino称重传感器和 HX711 放大器&#xff08;数字秤&#xff09; Arduino with Load Cell and HX711 Amplifier (Digital Scale) In this guide, you’ll learn how to create a digital scale with the Arduino using a load cell and the HX711 amplifier. First, you’l…

如何在微信小程序使用vant 进行自定义底部tabbar组件

在微信小程序中使用 Vant 自定义底部 TabBar 需要进行以下步骤&#xff1a; 一、首先&#xff0c;你需要在 app.json 文件中配置自定义 TabBar。 在 "tabBar" 字段中&#xff0c;设置 "custom" 为 true&#xff0c;表示使用自定义 TabBar。 app.json示例…