JavaScript数组对象的浅拷贝与深拷贝(二)实现对象深拷贝的方法(5种)
JavaScript实现对象深拷贝的方法(5种)
- 知识回调(不懂就看这儿!)
- 场景复现
- 实现对象深拷贝的五种方法
- 1.json暴力转化
- 2.es6扩展运算符
- 3.for in循环遍历对象
- 4.Object.assign()对象的合并
- 5.利用循环和递归的方式
- 实现对象浅拷贝的三种方法
- 1.concat、slice返回一个新数组
- 2.Object.assign()方法
- 3.遍历对象(通用方法)
知识回调(不懂就看这儿!)
知识专栏 | 专栏链接 |
---|---|
JavaScript知识专栏 | https://blog.csdn.net/xsl_hr/category_12024214.html?spm=1001.2014.3001.5482 |
JavaScript深浅拷贝的区别+图解原理 | https://blog.csdn.net/XSL_HR/article/details/129838095?spm=1001.2014.3001.5501 |
有关JavaScript的相关知识可以前往JavaScript知识专栏查看复习!!
场景复现
在上期文章中,我们从底层原理方面对JavaScript数组对象的浅拷贝和深拷贝进行了详细的介绍,看完上期文章之后,想必大家对浅拷贝与深拷贝都有了一定的认识,而本期文章将分享五个非常实用的深拷贝方法和三个实用的浅拷贝方法。
好的深拷贝方法有什么作用?
- 首先,深拷贝的学习对于我们在项目开发中进行数据处理是非常有用的。
- 深拷贝原理和方法的学习能够帮助我们规范代码,提高代码的有效性。
- 通知深拷贝方法的学习能够更好地帮助我们解决因为拷贝方式不当而产生的bug。节约更多debug的时间。
下面我们来通过代码示例来详细介绍五种深拷贝的方法。 👇👇👇
实现对象深拷贝的五种方法
1.json暴力转化
通过JSON.stringify()
和 JSON.parse()
将对象转为字符串之后在转为对象。
var obj = {name:'123'}
var obj2 = JSON.parse(JSON.stringify(obj))
var arr = ['old', 1, true, ['old1', 'old2'], {old: 1}]
var new_arr = JSON.parse(JSON.stringify(arr))
console.log(new_arr);
- 这种简单粗暴的方式有局限性,当值为
undefined
、function
、symbol
会在转换过程中被忽略。JSON.stringify()
不仅可拷贝数组还能拷贝对象(但不能拷贝函数,也不能解决循环引用问题)
2.es6扩展运算符
var obj = {name:'123',age:13};
var obj2 = {...obj}
只能深度拷贝对象的第一层,如果对象中的属性也是对象的话,没有办法进行深度拷贝的。
3.for in循环遍历对象
var obj = {name: "小明",age: 20}var obj1 = {}for (var key in obj) {//遍历属性值,深拷贝obj1[key] = obj[key]}console.log(obj1);
var deepCopy = function(target) {// 只拷贝对象if (typeof target !== 'object') return target;// 根据obj的类型判断是新建一个数组还是一个对象var result = Array.isArray(obj) ? [] : {};for (var key in target) {// 遍历obj,并且判断是obj的属性才拷贝(不能拷贝原型对象的属性)if (target.hasOwnProperty(key)) {// 判断属性值的类型,如果是对象递归调用深拷贝result[key] = typeof target[key] === 'object' ? deepCopy(target[key]) : target[key];}}return result;
}
其中上述方法一、方法三都解决不了循环引用的问题。
4.Object.assign()对象的合并
利用
Object.assign()
, 第一个参数必须是空对象
var obj = {name:'123',age:13};
var obj2 = Object.assign({},obj1);
5.利用循环和递归的方式
function deepClone(obj, newObj) {var newObj = newObj || {};for (let key in obj) {if (typeof obj[key] == 'object') {newObj[key] = (obj[key].constructor === Array) ? [] : {}deepClone(obj[key], newObj[key]);} else {newObj[key] = obj[key]}}return newObj;
}
在循环递归中需要注意设置临界值
(typeof obj[key] == ‘object’)
,否则会造成死循环。
循环递归可以处理对象中嵌套数组或对象的问题。相当于第三种方法的优化。
实现对象浅拷贝的三种方法
1.concat、slice返回一个新数组
数组的浅拷贝可用concat
、slice
返回一个新数组的特性来实现拷贝
var arr = ['old', 1, true, null, undefined];
var new_arr = arr.concat(); // 或者var new_arr = arr.slice()也是一样的效果;
new_arr[0] = 'new';
console.log(arr); // ["old", 1, true, null, undefined]
console.log(new_arr); // ["new", 1, true, null, undefined]
2.Object.assign()方法
let target = {};
let source = { a: { b: 2 } };
Object.assign(target, source);
console.log(target); // { a: { b: 10 } };
source.a.b = 10;
console.log(source); // { a: { b: 10 } };
console.log(target); // { a: { b: 10 } };
但是如果数组嵌套了对象或者数组的话用concat
、slice
拷贝只要有修改会引起新旧数组都一起改变了,比如:
var arr = [{old: 'old'}, ['old']];
var new_arr = arr.concat();
arr[0].old = 'new';
new_arr[1][0] = 'new';
console.log(arr); // [{old: 'new'}, ['new']]
console.log(new_arr); // [{old: 'new'}, ['new']]
3.遍历对象(通用方法)
实现思路:遍历对象,把属性和属性值都放在一个新的对象里
var shallowCopy = function (obj) {// 只拷贝对象if (typeof obj !== 'object') return;// 根据obj的类型判断是新建一个数组还是一个对象var newObj = Array.isArray(obj) ? [] : {};// 遍历obj,并且判断是obj的属性才拷贝for (var key in obj) {if (obj.hasOwnProperty(key)) {newObj[key] = obj[key];}}return newObj;
}
- 如果数组元素是基本类型,就会拷贝一份,互不影响,而如果是对象或者数组,就会只拷贝对象和数组的引用,这样我们无论在新旧数组进行了修改,两者都会发生变化。这种叫浅拷贝。
- 深拷贝就是指完全的拷贝一个对象,即使嵌套了对象,两者也相互分离,修改一个对象的属性,也不会影响另一个。
以上就是关于实现对象深拷贝与浅拷贝的方法的分享,相信看完这篇文章的小伙伴们一定能运用这些方法在项目开发中。当然,可能有不足的地方,欢迎大家在评论区留言指正!
相关文章:

JavaScript数组对象的浅拷贝与深拷贝(二)实现对象深拷贝的方法(5种)
JavaScript实现对象深拷贝的方法(5种)知识回调(不懂就看这儿!)场景复现实现对象深拷贝的五种方法1.json暴力转化2.es6扩展运算符3.for in循环遍历对象4.Object.assign()对象的合并5.利用循环和递归的方式实现对象浅拷贝…...

iPhone屏幕适配(之屏幕尺寸)
Device screen size 各设备屏幕尺寸 DeviceDimensions (portrait)iPhone 14 Pro Max430x932 pt (1290x2796 px 3x)iPhone 14 Pro393x852 pt (1179x2556 px 3x)iPhone 14 Plus428x926 pt (1284x2778 px 3x)iPhone 14390x844 pt (1170x2532 px 3x)iPhone 13 Pro Max428x926 pt (…...

手机变砖修复神器之 8 个的 Android手机系统修复工具
如果您经常在 Android 设备上遇到问题,则需要找到最好的 Android 系统修复应用程序并使用它来一劳永逸地解决您的问题。如果您不确定执行此操作的好应用是什么,我们在这里为您列出了一些最好的 Android 修复软件。 虽然现在出货的 Android 手机相当稳定…...

稀疏矩阵(Sparse Matrix)
1.背景 在数据科学和深度学习等领域常会采用矩阵格式来存储数据,但当矩阵较为庞大且非零元素较少时, 如果依然使用dense的矩阵进行存储和计算将是极其低效且耗费资源的。所以,通常我们采用Sparse稀疏矩阵的方式来存储矩阵,提高存储…...

深度学习中的损失函数
文章目录一. Loss函数1. 均方差损失(Mean Squared Error Loss)2. 平均绝对误差损失(Mean Absolute Error Loss)3.(Huber Loss)4. 分位数损失(Quantile Loss)5. 交叉熵损失࿰…...

English Learning - L2 语音作业打卡 辅音咬舌音 [θ] [ð] Day29 2023.3.21 周二
English Learning - L2 语音作业打卡 辅音咬舌音 [θ] [] Day29 2023.3.21 周二💌发音小贴士:💌当日目标音发音规则/技巧:🍭 Part 1【热身练习】🍭 Part2【练习内容】🍭【练习感受】🍓元音 [θ]…...

【原始者-综述】
目录知识框架No.1 AcwingNo.2 LeetcodeNo.3 PTANo.4 蓝桥No.5 牛客网No.6 代码随想录知识框架 No.1 Acwing 那就点击这里转向自己的Acwing题解咯 单调栈,动态规划,贪心,回溯,二叉树,站与队列,双指针&#…...

C++内存模型
目录 一.内存分区 二,分区顺序 1 程序运行前 2 程序运行后 3.new操作符 一.内存分区 内存分区意义:不同区域存放的数据,赋予不同的生命周期, 给我们更大的灵活编程 内存可以分为以下几个区: 代码区:存放函数体的二进制代码…...

八股+面经
文章目录项目介绍Java基础MapHashMap v.s Hashtable(5点)ConcurrentHashMap v.s Hashtable(2点)代理模式1. 静态代理2. 动态代理2.1 JDK 动态代理机制2.2 CGLIB 动态代理机制Java并发线程volatilesynchronized线程池JVM类加载机制垃圾回收(GC)1. 引用类型…...

MySQL更新数据流程
1.mysql三种重要日志 redo log(重做日志):存在于引擎层,物理存储,通过设置innodb_flush_log_at_trx_xommit1 让其持久化到磁盘,保证引擎的crash-safe能力,遵从WAL技术(Write-Ahead …...

测试开发进阶系列课程
测试开发系列课程1.完善程序思维--------案列:图书管理系统的创建**(一)图书管理系统的创建**1.完善程序思维--------案列:图书管理系统的创建 (一)图书管理系统的创建 1.在main中写入主函数,…...

Qt源码阅读(三) 对象树管理
对象树管理 个人经验总结,如有错误或遗漏,欢迎各位大佬指正 😃 文章目录对象树管理设置父对象的作用设置父对象(setParent)完整源码片段分析对象的删除夹带私货时间设置父对象的作用 众所周知,Qt中,有为对象设置父对象…...

【Python入门第四十二天】Python丨NumPy 数组裁切
裁切数组 python 中裁切的意思是将元素从一个给定的索引带到另一个给定的索引。 我们像这样传递切片而不是索引:[start:end]。 我们还可以定义步长,如下所示:[start:end:step]。 如果我们不传递 start&…...

Anaconda配置Python新版本tensorflow库(CPU、GPU通用)的方法
本文介绍在Anaconda环境中,下载并配置Python中机器学习、深度学习常用的新版tensorflow库的方法。 在之前的两篇文章基于Python TensorFlow Estimator的深度学习回归与分类代码——DNNRegressor(https://blog.csdn.net/zhebushibiaoshifu/article/detail…...

加载模型时出现 OSError: Unable to load weights from pytorch checkpoint file 报错的解决
加载模型时出现 OSError: Unable to load weights from pytorch checkpoint file 报错的解决报错信息原因查明网传解决措施好消息我的解决措施报错信息 查了下,在网上还是个比较常见的报错 一般为加载某模型时突然报错 原因查明 一般为下载某个 XXX_model.bin 的…...

sessionStorage , localStorage 和cookie的区别
一.sessionStorage(临时存储)sessionStorage是HTML5中新增的Web Storage API之一,用于在浏览器中存储键值对数据,与localStorage类似,但是sessionStorage存储的数据在会话结束时会被清除。可以通过以下方式使用sessionStorage:存储…...

C# 实例详解委托之Func、Action、delegate
委托是.NET编程的精髓之一,在日常编程中经常用到,在C#中实现委托主要有Func、Action、delegate三种方式,这个文章主要就这三种委托的用法通过实例展开讲解。 【Func】:Func是带返回值的委托: 原型函数如下(以下展示的…...

如何选电脑
1、CPU(中央处理器) 怎么看CPU型号:CPU:系列-代数等级核心显卡型号电压后缀 例如CPU:i7-10750H : 1、系列:Intel的酷睿i3、i5、i7、i9这四个系列的CPU,数字越大就代表越高端。 2、代数:代表…...

SpringBoot项目创建
如果使用spring的源地址创建项目失败,就使用 阿里云的springBoot项目创建地址:https://start.aliyun.com/ 1.new 一个新的项目: 2.选择合适的版本java的JDK和maven项目 3.选择spring web依赖 4.直接finish 5. 删除无用的包,然后…...

神经衰弱该如何判断?确诊为神经衰弱,日常要做好这7大护理!
神经衰弱是由于长时间处于紧张或者压力的情况下导致精神出现兴奋或者疲乏现象而伴随着一系列症状。如情绪烦恼、容易激怒、睡眠障碍、肌肉出现紧张性疼痛等,生活中有很多人在自己的不到休息或者遇到强大打击时就会嘲笑自己患上神经衰弱。甚至一些会盲目采取措施&…...

Linux之进程替换
进程替换1.什么是进程替换2.替换函数2.1 execl函数2.2 execv函数2.3 execlp函数2.4 execvp函数2.5 在自己的C程序上如何运行其他语言的程序?2.6 execle 函数2.7 小结3.一个简易的shell1.什么是进程替换 fork()之后,父子各自执行父进程代码的一部分&…...

关于清除浮动
浮动最早是用来做图文排版,为了让块级元素同行显示,而html中块元素是有自己的排列规则,一般独占一行。所以有了浮动元素,一旦元素浮动了就会脱离文档流,产生问题。怎么去清除浮动:(1)…...

Uber H3 index 地图索引思考
H3 是 uber 设计的六边形空间索引,go 语言操作包是 h3-go,可以通过经纬度获取所在的 h3 六边形边界,每个经纬度对应的六边形都是确定的,每个六边形唯一对应了一个 h3index。在业务开发中,我们可以通过 h3index 来对地理…...

多线程的几种状态
Java-多线程的几种状态🔎1.NEW( 系统中线程还未创建,只是有个Thread对象)🔎2.RUNNABLE( (就绪状态. 又可以分成正在工作中和即将开始工作)🔎3.TERMINATED(系统中的线程已经执行完了,Thread对象还在)🔎4.TIMED_WAITING(指定时间等待…...

【算法题】1574. 删除最短的子数组使剩余数组有序
题目: 给你一个整数数组 arr ,请你删除一个子数组(可以为空),使得 arr 中剩下的元素是 非递减 的。 一个子数组指的是原数组中连续的一个子序列。 请你返回满足题目要求的最短子数组的长度。 示例 1: …...

理解对数——金融问题中的自然对数(以e为底的对数)
第3章 金融问题(Financial Matters)——金融问题中的自然对数If thou lend moneyto any ofMy people. ...thou shalt not beto him as a creditor;neither shall yelay upon him interest.(如果你借钱给我的任何人。 ……你不应该是他的债权人;也不可向他加息。)——…...

vue2进阶学习之路
HTML、CSS和JavaScript基础 在学习Vue2之前,需要掌握HTML、CSS和JavaScript的基础知识。包括HTML的标签、CSS的布局和样式、JavaScript的变量类型、条件语句、循环语句等。 Vue2的基础知识 掌握Vue2的基本概念和语法,包括Vue2实例、数据绑定、指令、组件…...

决策树ID3算法
1. 决策树ID3算法的信息论基础 机器学习算法其实很古老,作为一个码农经常会不停的敲if, else if, else,其实就已经在用到决策树的思想了。只是你有没有想过,有这么多条件,用哪个条件特征先做if,哪个条件特征后做if比较优呢&#…...

C++模板基础(一)
函数模板(一) ● 使用 template 关键字引入模板: template void fun(T) {…} – 函数模板的声明与定义 – typename 关键字可以替换为 class ,含义相同 – 函数模板中包含了两对参数:函数形参 / 实参;模板形…...

生产者消费者模型线程池(纯代码)
目录 生产者消费者模型 条件变量&&互斥锁(阻塞队列) makefile Task.hpp BlockQueue.hpp BlockQueueTest.cc 信号量&&互斥锁(环形队列) makefile RingQueue.hpp RingQueueTest.cc 线程池(封…...