【面试题】马上金九银十了,简历该准备起来了,面试题你准备好了吗 ?浅谈 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.mfbz.cn/a/740677.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

编程精粹—— Microsoft 编写优质无错 C 程序秘诀 08:剩下的就是态度问题

这是一本老书,作者 Steve Maguire 在微软工作期间写了这本书,英文版于 1993 年发布。2013 年推出了 20 周年纪念第二版。我们看到的标题是中译版名字,英文版的名字是《Writing Clean Code ─── Microsoft’s Techniques for Developing》&a…

vue配置中的process.env

项目中的.env开头的文件是否知道是干什么的呢 主要是为了区分测试环境还是生产环境env.development为测试环境 # 测试环境 NODE_ENV development VUE_APP_BASE_API http://xxxxxxxxx // 命名一定要以 VUE_APP_ 开头,要不然根本取不到 .env.production为生产环境…

企业文件传输系统只能传输?分享功能同样重要!(上)

在当今的商业世界里,企业间的协作和信息交流已经变得极其重要,特别是在处理那些庞大的文件时。想象一下,设计图、高清视频、大数据分析,还有软件开发包,这些文件的大小往往达到GB甚至TB级别,它们是企业日常…

猫头虎 分享已解决Error || **Data Leakage**: `Unexpectedly high validation performance`

猫头虎 分享已解决Error || Data Leakage: Unexpectedly high validation performance 🐯 摘要 📄 大家好,我是猫头虎,一名专注于人工智能领域的博主。在AI开发中,我们经常会遇到各种各样的错误,其中Data…

LONGHEADS:无需训练的多头注意力长文本处理框架

大模型(LLMs)在处理海量文本数据时展现出了前所未有的能力。然而这些模型在面对超出其训练时所见序列长度的长文本时存在两个主要问题:一是模型对于超出预训练长度的文本难以有效泛化,二是注意力机制的二次方时间复杂度导致计算成…

SAPUI5基础知识8 - 模块(Module)的使用

1. 背景 在SAPUI5中,几乎所有东西都是一个模块(例如:控件,控制器,组件等等),通过依赖管理,模块间可以相互调用。这样做的好处是,可以仅在需要时才去加载必需的模块&…

【力扣】从前序与中序遍历序列构造二叉树

🔥博客主页: 我要成为C领域大神 🎥系列专栏:【C核心编程】 【计算机网络】 【Linux编程】 【操作系统】 ❤️感谢大家点赞👍收藏⭐评论✍️ 本博客致力于分享知识,欢迎大家共同学习和交流。 给定两个整数数…

React+TS 从零开始教程(3):useState

源码链接:下载 在开始今天的内容之前呢,我们需要先看一个上一节遗留的问题,就是给属性设置默认值。 我们不难发现,这个defaultProps已经被废弃了,说明官方并不推荐这样做。其实,这个写法是之前类组件的时候…

SpringCloud Alibaba Sentinel 流量控制之流控效果实践总结

当 QPS 超过某个阈值的时候,则采取措施进行流量控制。流量控制的效果包括以下几种:直接拒绝、Warm Up、匀速排队/排队等待。对应 FlowRule 中的 controlBehavior 字段。 注意:若使用除了直接拒绝之外的流量控制效果,则调用关系限流…

【JS】上传文件显示文件的为空,显示的文件参数内容只有uid

上传的文件参数file里面只包含uid,没有其他信息 例子解决办法 例子 例如使用elment ui的el-upload组件上传文件,会导致上传的文件参数file里面只包含uid,没有其他信息,如图: 正确应为如下图: 解决办法 …

视图(views)

自学python如何成为大佬(目录):https://blog.csdn.net/weixin_67859959/article/details/139049996?spm1001.2014.3001.5501 下面通过一个例子讲解在Django项目中定义视图,代码如下: from django.http import HttpResponse # 导入响应对象 impo…

Idea启动服务报 Command line is too long

一、背景 合不同分支代码后,启动服务报 Error running Application, Command line is too long, Shorten the command line via JAR manifest or via a classpath file and rerun. 没有在意,然后点击了manifest 来进行 二、问题 然后自己在重新启动&…

情绪管理篇:让七情自然流露,不过分压抑也不掺杂极端的想法即可来去自如

情绪管理篇: 人有七情,本属常理,该哭的时候哭、该笑的时候笑、该怒的时候怒、该忧的时候忧 学习圣贤之学,并非让我们像木头人一样,枯木死灰,而要让自己不要被七情所缠缚、被七情所乱心,我们的喜…

最新《pvz植物大战僵尸杂交版》整合安装包,全面支持Android、ios、Windows,附教程!

今天,阿星要聊聊最近全网大火的一款老游戏——《植物大战僵尸》杂交版。 虽然它不是什么3A大作,但在阿星的心里,它永远是那个让人回味无穷的经典。记得十年前,阿星和大多数玩家一样,玩的都是盗版。那时候的《植物大战…

三品PDM电子行业解决方案介绍 电子企业PDM应用效果

随着全球化和技术创新的不断推进,电子行业正经历着前所未有的发展机遇。然而,随之而来的挑战也日益凸显,尤其是在产品数据管理PDM方面。本文将探讨电子行业在PDM方面的需求,并提出相应的解决方案,以帮助企业提升效率和…

项目中eventbus和rabbitmq配置后,不起作用

如下:配置了baseService层和SupplyDemand层得RabbitMQ和EventBus 但是在执行订阅事件时,发送得消息在base项目中没有执行,后来发现是虚拟机使用得不是一个,即上图中得EventBus下得VirtualHost,修改成一直就可以了

Latex学习之“usefont”用法

Latex学习之“\usefont”用法 一、通俗的解释 \usefont 是 LaTeX 中的一个命令,用于在文档中临时改变字体,其基本语法如下: \usefont{字体编码}{字体族}{字体系列}{字体形状}这样看起来好像蛮抽象,你可能以及晕了,什…

警告,恶意域名疯狂外联,原因竟然是……

前言 在某个风和日丽的下午,突然收到客户那边运维发过来的消息说我司的DTA设备在疯狂告警,说存在恶意域名外联,我急忙背上小背包前往客户现场,经过与客户协同排查,最终确定该事件为一起挖矿病毒引起的恶意域名外联事件…

鸿蒙开发系统基础能力:【@ohos.hiTraceChain (分布式跟踪)】

分布式跟踪 本模块提供了端侧业务流程调用链跟踪的打点能力,包括业务流程跟踪的启动、结束、信息埋点等能力。 说明: 本模块首批接口从API version 8开始支持。后续版本的新增接口,采用上角标单独标记接口的起始版本。 导入模块 import hi…

xss初识(xss-lab)

XSS跨站脚本 XSS漏洞概述 XSS被称为跨站脚本攻击(Cross-site scripting),由于和CSS(Cascading Style Sheets) 重名,所以改为XSS。 XSS主要基于javascript语言完成恶意的攻击行为,因为javascri…