字节一面:深拷贝浅拷贝的区别?如何实现一个深拷贝?

前言

最近博主在字节面试中遇到这样一个面试题,这个问题也是前端面试的高频问题,我们经常需要对后端返回的数据进行处理才能渲染到页面上,一般我们会讲数据进行拷贝,在副本对象里进行处理,以免玷污原始数据,这里就会设计深拷贝浅拷贝的知识,博主在这给大家细细道来。


🚀 作者简介:程序员小豪,全栈工程师,热爱编程,曾就职于蔚来、腾讯,现就职于某互联网大厂,技术栈:Vue、React、Python、Java
🎈 本文收录于小豪的前端系列专栏,后续还会更新前端入门以及前端面试的一些相关文章,手把手带你从零学习前端到面试找工作,并如果有想进入前端领域工作的同学,这个前端专栏会对你有所帮助,欢迎关注起来呀
🌼 本人也会持续的去关注AIGC以及人工智能领域的一些动向并总结到博客中,大家感兴趣的可以关注一下我的人工智能专栏
🌊 云原生的入门学习系列,大家有兴趣的可以看一看

目录

  • 一、数据类型存储
  • 二、浅拷贝
    • Object.assign
    • slice()
    • concat()
    • 拓展运算符
  • 三、深拷贝
    • _.cloneDeep()
    • jQuery.extend()
    • JSON.stringify()
    • 循环递归
  • 四、区别
    • 小结
  • 结语

一、数据类型存储

前面文章我们讲到,JavaScript中存在两大数据类型:

  • 基本类型
  • 引用类型

基本类型数据保存在在栈内存中

引用类型数据保存在堆内存中,引用数据类型的变量是一个指向堆内存中实际对象的引用,存在栈中

二、浅拷贝

浅拷贝,指的是创建新的数据,这个数据有着原始数据属性值的一份精确拷贝

如果属性是基本类型,拷贝的就是基本类型的值。如果属性是引用类型,拷贝的就是内存地址

即浅拷贝是拷贝一层,深层次的引用类型则共享内存地址

下面简单实现一个浅拷贝

function shallowClone(obj) {const newObj = {};for(let prop in obj) {if(obj.hasOwnProperty(prop)){newObj[prop] = obj[prop];}}return newObj;
}

JavaScript中,存在浅拷贝的现象有:

  • Object.assign
  • Array.prototype.slice(), Array.prototype.concat()
  • 使用拓展运算符实现的复制

Object.assign

var obj = {age: 18,nature: ['smart', 'good'],names: {name1: 'fx',name2: 'xka'},love: function () {console.log('fx is a great girl')}
}
var newObj = Object.assign({}, fxObj);

slice()

const fxArr = ["One", "Two", "Three"]
const fxArrs = fxArr.slice(0)
fxArrs[1] = "love";
console.log(fxArr) // ["One", "Two", "Three"]
console.log(fxArrs) // ["One", "love", "Three"]

concat()

const fxArr = ["One", "Two", "Three"]
const fxArrs = fxArr.concat()
fxArrs[1] = "love";
console.log(fxArr) // ["One", "Two", "Three"]
console.log(fxArrs) // ["One", "love", "Three"]

拓展运算符

const fxArr = ["One", "Two", "Three"]
const fxArrs = [...fxArr]
fxArrs[1] = "love";
console.log(fxArr) // ["One", "Two", "Three"]
console.log(fxArrs) // ["One", "love", "Three"]

三、深拷贝

深拷贝开辟一个新的栈,两个对象属完成相同,但是对应两个不同的地址,修改一个对象的属性,不会改变另一个对象的属性

常见的深拷贝方式有:

  • _.cloneDeep()
  • jQuery.extend()
  • JSON.stringify()
  • 手写循环递归

_.cloneDeep()

const _ = require('lodash');
const obj1 = {a: 1,b: { f: { g: 1 } },c: [1, 2, 3]
};
const obj2 = _.cloneDeep(obj1);
console.log(obj1.b.f === obj2.b.f);// false

jQuery.extend()

const $ = require('jquery');
const obj1 = {a: 1,b: { f: { g: 1 } },c: [1, 2, 3]
};
const obj2 = $.extend(true, {}, obj1);
console.log(obj1.b.f === obj2.b.f); // false

JSON.stringify()

const obj2=JSON.parse(JSON.stringify(obj1));

但是这种方式存在弊端,会忽略undefinedsymbol函数

const obj = {name: 'A',name1: undefined,name3: function() {},name4:  Symbol('A')
}
const obj2 = JSON.parse(JSON.stringify(obj));
console.log(obj2); // {name: "A"}

循环递归

function deepClone(obj, hash = new WeakMap()) {if (obj === null) return obj; // 如果是null或者undefined我就不进行拷贝操作if (obj instanceof Date) return new Date(obj);if (obj instanceof RegExp) return new RegExp(obj);// 可能是对象或者普通的值  如果是函数的话是不需要深拷贝if (typeof obj !== "object") return obj;// 是对象的话就要进行深拷贝if (hash.get(obj)) return hash.get(obj);let cloneObj = new obj.constructor();// 找到的是所属类原型上的constructor,而原型上的 constructor指向的是当前类本身hash.set(obj, cloneObj);for (let key in obj) {if (obj.hasOwnProperty(key)) {// 实现一个递归拷贝cloneObj[key] = deepClone(obj[key], hash);}}return cloneObj;
}

四、区别

下面首先借助两张图,可以更加清晰看到浅拷贝与深拷贝的区别

从上图发现,浅拷贝和深拷贝都创建出一个新的对象,但在复制对象属性的时候,行为就不一样

浅拷贝只复制属性指向某个对象的指针,而不复制对象本身,新旧对象还是共享同一块内存,修改对象属性会影响原对象

// 浅拷贝
const obj1 = {name : 'init',arr : [1,[2,3],4],
};
const obj3=shallowClone(obj1) // 一个浅拷贝方法
obj3.name = "update";
obj3.arr[1] = [5,6,7] ; // 新旧对象还是共享同一块内存console.log('obj1',obj1) // obj1 { name: 'init',  arr: [ 1, [ 5, 6, 7 ], 4 ] }
console.log('obj3',obj3) // obj3 { name: 'update', arr: [ 1, [ 5, 6, 7 ], 4 ] }

但深拷贝会另外创造一个一模一样的对象,新对象跟原对象不共享内存,修改新对象不会改到原对象

// 深拷贝
const obj1 = {name : 'init',arr : [1,[2,3],4],
};
const obj4=deepClone(obj1) // 一个深拷贝方法
obj4.name = "update";
obj4.arr[1] = [5,6,7] ; // 新对象跟原对象不共享内存console.log('obj1',obj1) // obj1 { name: 'init', arr: [ 1, [ 2, 3 ], 4 ] }
console.log('obj4',obj4) // obj4 { name: 'update', arr: [ 1, [ 5, 6, 7 ], 4 ] }

小结

前提为拷贝类型为引用类型的情况下:

  • 浅拷贝是拷贝一层,属性为对象时,浅拷贝是复制,两个对象指向同一个地址
  • 深拷贝是递归拷贝深层次,属性为对象时,深拷贝是新开栈,两个对象指向不同的地址

结语

各位看官老爷们好,小豪已经建立了技术交流群,如果你很感兴趣,可以私信我加入我的社群。

📝社群中不定时会有很多活动,例如学习资料分享、大厂面经分享、技术讨论、行业大佬创业杂谈等等。

📝本人目前是在互联网大厂正式工作,也有过多个大厂的工作经历,加入社群也会有简历修改辅导,模拟面试,手把手项目实战教学,大厂工作内推机会以及大厂面试题解析分享等福利。

📝社群方向很多,相关领域有Web全栈(前后端)、人工智能、AIGC、自媒体变现、前沿科技文章分享、论文精读等等。

📝不管你是多新手的小白,都欢迎你加入社群中讨论、聊天、分享,加速助力你成为下一个技术大佬!也随时欢迎您跟我沟通,一起交流,一起成长。变现、进步、技术、资料、项目、你想要的这里都会有

📝网络的风口只会越来越大,风浪越大,鱼越贵!欢迎您加入社群~一个人可以或许可以走的很快,但一群人将走的更远!

📝想都是问题,做都是答案!行动起来吧!欢迎评论区or后台与我沟通交流,也欢迎您扫描下方二维码直接加入到我的交流社群!(微信:adcoderhao)

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

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

相关文章

力扣 -- 10. 正则表达式匹配

解题步骤&#xff1a; 参考代码&#xff1a; class Solution { public:bool isMatch(string s, string p) {int ms.size();int np.size();//处理后续映射关系s s;//处理后续映射关系p p;vector<vector<bool>> dp(m1,vector<bool>(n1));//初始化dp[0][0]true…

支付宝支付模块开发

生成二维码 使用Hutool工具类生成二维码 引入对应的依赖 <dependency><groupId>cn.hutool</groupId><artifactId>hutool-all</artifactId><version>5.7.5</version> </dependency><dependency><groupId>com.go…

公司知识库搭建步骤,知识库建设与运营的四个步骤分享

在知识管理方面&#xff0c;团队中的每一员&#xff0c;都像是一名独行侠&#xff0c;自己的知识&#xff0c;满足自己的需要&#xff0c;这其中&#xff0c;就造成了很多无意义的精力消耗。 公司知识库搭建必要性 比如&#xff0c;一名员工撰写一QA文档&#xff0c;并没有将它…

国庆《乡村振兴战略下传统村落文化旅游设计》许少辉八一新书行将售罄

国庆《乡村振兴战略下传统村落文化旅游设计》许少辉八一新书行将售罄 国庆《乡村振兴战略下传统村落文化旅游设计》许少辉八一新书行将售罄

【CUDA编程概念】一、什么是bank conflict?

前言 搜了不少答案&#xff0c;大多是在避免Bank Conflict&#xff0c;很难找到一个关于Bank Conflict的详细定义&#xff0c;这里找了些资料来尝试解释下&#xff1b; 一、基础概念 先简单复习下相关概念 GPU调度执行流程&#xff1a; SM调度单位为一个warp&#xff08;一…

Linux:修改mvn命令使用的maven路径

要在 Linux 上更改 Maven 的版本&#xff0c;需要调整 PATH 环境变量以指向所需版本的 Maven 安装目录。 打开终端或命令行界面。 使用文本编辑器打开 /etc/profile 文件&#xff1a; vi /etc/profile在文件的末尾添加以下行&#xff0c;将 PATH 环境变量指向新的 Maven 安装目…

4项简化IT服务台任务的ChatGPT功能

近几个月&#xff0c;随着人工智能聊天机器人 ChatGPT 风靡全球&#xff0c;用户可以通过它生成脚本、文章、运动计划表等。同时&#xff0c;这项技术在各行各业都能够进行无穷无尽的应用&#xff0c;在本文中&#xff0c;我们将探讨这项现代技术如何帮助ITSM团队提升服务交付和…

面试题六:Promise的使用,一文详细讲解

含义 Promise是异步编程的一种解决方案&#xff0c;比传统的解决方案&#xff08;回调函数和事件&#xff09;更合理更强大。 所谓Promise&#xff0c;简单说就是一个容器&#xff0c;里面保存着某个未来才会结束的事件 (通常是一个异步操作)的结果。从语法上说&#xff0c;P…

【JavaEE初阶】 计算机是如何工作的

文章目录 &#x1f332;计算机发展史&#x1f38b;冯诺依曼体系&#xff08;Von Neumann Architecture&#xff09;&#x1f38d;CPU 基本工作流程&#x1f4cc;逻辑门&#x1f388;电子开关 —— 机械继电器(Mechanical Relay)&#x1f388;门电路(Gate Circuit)NOT GATE&…

ElasticSearch深度分页解决方案

文章目录 概要ElasticSearch介绍es分页方法es分页性能对比表方案对比 From/Size参数深度分页问题Scroll#性能对比向前翻页 总结个人思考 概要 好久没更新文章了&#xff0c;最近研究了一下es的深分页解决方案。和大家分享一下&#xff0c;祝大家国庆节快乐。 ElasticSearch介…

windows下python开发环境的搭建 python入门系列 【环境搭建篇】

在正式学习Python之前要先搭建Python开发环境。由于Python是跨平台的&#xff0c;所以可以在多个操作系统上进行编程 一、python的下载安装与配置 1、Python解释器 1. 要进行Python开发&#xff0c;首先需要Python解释器&#xff0c;这里说的安装Python就是安装Python解释器…

利用mAP计算yolo精确度

当将yolo算法移植部署在嵌入式设备上&#xff0c;为了验证算法的准确率。将模型测试的结果保存为txt文件&#xff08;每一个txt文件&#xff0c;对应一个图片&#xff09;。此外&#xff0c;需要将数据集中的标签由[x,y,w,h]转为[x1,y1,x2,y2]。最后&#xff0c;运行验证代码 …

极简非凡react hooks+arcoDesign+vite后台管理模板

最近捣鼓了一个vite4搭建react18后台模板&#xff0c;搭载了字节团队react组件库Arco Design&#xff0c;整体编译运行顺滑衔接。支持多种模板布局、暗黑/亮色模式、国际化、权限验证、多级路由菜单、tabview标签栏快捷菜单、全屏控制等功能。 使用技术 "arco-design/web…

如何写一份完整的职业规划书?

写职业规划书&#xff0c;确定今后几年的一个发展方向&#xff08;职业规划建议越早越好&#xff09;&#xff0c;帮助自己收获更大的成功。普通的职业规划书书写起来十分简单&#xff0c;没有想象中那样复杂&#xff0c;只需要包括基本的部分&#xff0c;就可以轻轻松松完成。…

【面试经典150 | 数组】除自身以外数组的乘积

文章目录 写在前面Tag题目来源题目解读解题思路方法一&#xff1a;记录左右乘积空间优化 写在最后 写在前面 本专栏专注于分析与讲解【面试经典150】算法&#xff0c;两到三天更新一篇文章&#xff0c;欢迎催更…… 专栏内容以分析题目为主&#xff0c;并附带一些对于本题涉及到…

从 低信噪比陆上地震记录 解决办法收集 到 走时层析反演中的折射层析调研

目录 (前言1) 关于背景的回答:(前言2) 现有的降低噪声, 提高信噪比的一些特有方法的论文资料 (传统策略):1. 关于波形反演与走时层析反演2. 折射层析3. 用一个合成数据来解释折射层析反演的思路4. 其他层析反演方法:5. 关于层析反演的一些TIPS (可补充)参考文献: 降噪有关资料参…

Android 视频通话分析总结

1、WireShark 解析视频流 1.1 安装插件 下载rtp_h264_extractor.lua文件&#xff0c;放入Wireshark安装目录 下载地址&#xff1a;https://download.csdn.net/download/tjpuzm/88381821 在init.lua中添加如下代码 dofile(DATA_DIR.."rtp_h264_extractor.lua") 重新…

【ARMv8 SIMD和浮点指令编程】NEON 加载指令——如何将数据从内存搬到寄存器(其它指令)?

除了基础的 LDx 指令,还有 LDP、LDR 这些指令,我们也需要关注。 1 LDNP (SIMD&FP) 加载 SIMD&FP 寄存器对,带有非临时提示。该指令从内存加载一对 SIMD&FP 寄存器,向内存系统发出访问是非临时的提示。用于加载的地址是根据基址寄存器值和可选的立即偏移量计算…

【数据结构】逻辑结构与物理结构

&#x1f984;个人主页:修修修也 &#x1f38f;所属专栏:数据结构 ⚙️操作环境:Visual Studio 2022 目录 &#x1f333;逻辑结构 1.集合结构 2.线性结构 3.树形结构 4.图形结构或网状结构 &#x1f333;物理结构 1.顺序存储结构 2.链式存储结构 结语 根据视点的不同,我…

华为ensp单臂路由及OSPF实验

单臂路由及OSPF实验 1.1实验背景 在这个实验中&#xff0c;我们模拟了一个复杂的网络环境&#xff0c;该网络环境包括多个子网和交换机。这个实验旨在帮助网络工程师和管理员了解如何配置单臂路由和使用开放最短路径优先&#xff08;OSPF&#xff09;协议来实现不同子网之间的…