js深拷贝与浅拷贝
1.浅拷贝概念
浅拷贝是其属性与拷贝源对象的属性共享相同引用,当你更改源或副本时,也可能(可能说的是只针对引用数据类型)导致其他对象也发生更改。
特性:
- 会新创建一个对象,即obj===obj2返回fasle;
- 对象中如果是基本数据类型会单独开辟一份空间存储,如果是引用数据类型则共用一个内存地址。即如果是基本数据类型新对象修改不会造成源对象值改变,但是如果是引用数据类型,修改会造成源对象属性同时被修改
2.var people1 = people不是浅拷贝
注意var people1 = people不是浅拷贝。只是对内存地址进行赋值,people1 === people 返回true,这种不是浅拷贝
// 这个种方式不是浅拷贝
var people = {name: 'allen'
}// 这里只是对内存地址进行赋值,people1 === people 返回true,这种不是浅拷贝
var people1 = people
people1.name = 'jason'
3.浅拷贝示例
浅拷贝:会新创建一个对象,对源对象的属性进行拷贝,使两者共享同一个地址。obj === obj2返回false。比如:var obj2 = Object.assign({}, obj)
说明:Object.assign()是浅拷贝,会生成一个新的对象。浅拷贝对于基本数据类型a,会重新单独开辟一份空间进行存储, 而对于引用数据类型b拷贝的是其内存地址,所以obj2和obj对于拷贝后的b是共用一份内存地址。所以如果修改obj2中b的b1的值,则obj中的b1的值也会改变
4.浅拷贝的方法(Object.create(),Object.assign(),扩展运算符)
4.1Object.create()
创建一个对象,会将源对象放到新对象的原型上(即会将obj对象放到obj2的原型上),返回一个新的对象。
var obj = {a: 1}
var obj2 = Object.create(obj)
obj.a = 2 //修改基本数据类型,源对象也会改变
console.log(obj === obj2); //false
console.log(obj,obj2);
4.2 Object.assign()
将对象属性进行合并,并返回新的对象,遇到重名对象会进行覆盖
var obj = {a: 1,b: {b1: 1}
}
var obj2 = Object.assign({}, obj)
obj.a = 2
obj.b.b1 = 2console.log(obj === obj2);
console.log(obj, obj2);
结果:源对象基本数据类型值没有改变,引用数据用的同一个会改变
4.3扩展运算符
var obj = {a: 1,b: {b1: 1}
}var obj2 = {...obj};
obj2.a = 3;
obj2.b.b1 = 2;console.log(obj === obj2);
console.log(obj, obj2);
结果:同上
5.深拷贝概念
深拷贝是指其属性与其拷贝的源对象的属性不共享相同的引用,当你更改源或副本时,可以确保不会导致其他对象也发生更改
6.深拷贝的方法
6.1JSON.parse(JSON.stringify())
原理:通过改变数据类型的形式进行深拷贝,JSON.stringify()将对象序列化成字符串,而JSON.parse()将字符串转为对象。注意不是JSON.stringify()是两个方法组合使用
var obj = {a: 1,b: {b1: 1}
}
var obj1 = JSON.parse(JSON.stringify(obj))
obj1.a = 2
obj1.b.b1 = 2
console.log(obj === obj2);
console.log(obj, obj2);
结果:基本数据类型和引用数据类型的改变都不会印象源对象
6.2 Lodash.cloneDeep()
cdn地址 : https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.21/lodash.min.js
import _ form "lodash";var obj = {a: 1,b: {b1: 1}
}
var obj1 = _.cloneDeep(obj)
obj1.a = 2
obj1.b.b1 = 2
7.深拷贝的原理
7.1主要考虑以下三个方面:
- 数据类型的划分
- 递归处理
- 循环引入的处理:循环引入即对象可以一直展开,无限嵌套,无限循环
7.1循环引入:
var obj = {};
obj.a = obj;
console.log(obj);
对象可以一直展开,无限嵌套,无限循环
8.手动实现深拷贝
8.1方式一:简单实现(只判断数据基本类型和针对对象数据结构)
- 判断数据类型,特殊类型直接返回;
- 遍历对象进行递归处理;
function deepClone(obj) {console.log(typeof obj);// 判断如果为null,不等于字符串的object,function, 为Date类型,RegRex类型则直接返回if (obj === null || typeof obj !== 'object' || typeof obj === 'function' || obj instanceof Date || obj instanceof RegExp) {return obj;}if (obj instanceof Object) {const newObj = {};for (let key in obj) {newObj[key] = deepClone(obj[key]);}// 注意是最后return不是在for循环中returnnewObj[key]return newObj;}}var obj = {a: 1,b: {b1: 1}}var obj2 = deepClone(obj);obj2.a = 2;obj2.b.b1 = 2console.log(obj === obj2);console.log(obj, obj2);
8.2 方式二(增强): 针对Map、Set、Array等结构进行深拷贝处理
- 判断数据类型,特殊类型直接返回;
- 遍历对象进行递归处理;
- 对Map,Set,Array数据结构进行处理
- 注意Map,Set,Array各自不同遍历及修改的方法
function deepClone(obj) {// 判断如果为null,不等于字符串的object,function, 为Date类型,RegRex类型则直接返回if (obj === null || typeof obj !== 'object' || typeof obj === 'function' || obj instanceof Date || obj instanceof RegExp) {return obj;}if (obj instanceof Set) { //对于Set数据结构(for of 循环;newSet.add(val)) const newObj = new Set();for (let val of obj) {newObj.add(deepClone(val));}return newObj;} else if (obj instanceof Map) { //对于Map数据结构(for of循环 map.set(key,val))const newObj = new Map();for (let [key, val] of obj) {newObj.set(key, deepClone(val));}return newObj;} else if (obj instanceof Array) { //对于数组数据结构(使用forEach进行循环push进行添加)const newObj = [];obj.forEach(item => {newObj.push(deepClone(newObj[item]));});return newObj} else if (obj instanceof Object) {const newObj = {};for (let key in obj) {newObj[key] = deepClone(obj[key]);}// 注意是最后return不是在for循环中returnnewObj[key]return newObj;} else {return obj;}}var newMap = new Map();newMap.set('key1', 12);newMap.set('key2', 13);var newSet = new Set();newSet.add('11');newSet.add('22');var obj = {a: 1,b: {b1: 1},c: {c1: [1, 2, 3]},d: newMap,f: newSet}var obj2 = deepClone(obj);obj2.a = 2;// 基本数据类型修改值obj2.b.b1 = 2// 数组改变值obj2.c.c1 = [2, 3, 4];// map集合修改key1obj2.d.set('key1','更改后的key1');// Set集合增加一个obj2.f.add('set集合增加的值');console.log(obj === obj2);console.log(obj, obj2);
8.3 方式三(循环引用的处理)
- 判断数据类型,特殊类型直接返回;
- 遍历对象进行递归处理;
- 对Map,Set,Array数据结构进行处理
- 注意Map,Set,Array各自不同遍历及修改的方法
如果有循环引用,使用方式二深拷贝处理,会一直循环导致内存溢出。map = new WeakMap()用于判断是否已经有过相同引用
function deepClone(obj, map = new WeakMap()) {// 判断如果为null,不等于字符串的object,function, 为Date类型,RegRex类型则直接返回if (obj === null || typeof obj !== 'object' || typeof obj === 'function' || obj instanceof Date || obj instanceof RegExp) {return obj;}// 循环引入处理(如果obj下的key的值为obj本身,则循环将obj的值设置到map的key中)// WeakMap的key只能是对象,Set、Map、Array、Object每个都设置map.set(obj,newObj);是因为每种数据结构都有可能存在循环引用if (map.get(obj)) {return map.get(obj);}if (obj instanceof Set) { //对于Set数据结构(for of 循环;newSet.add(val)) const newObj = new Set();map.set(obj, newObj);for (let val of obj) {newObj.add(deepClone(val, map));}return newObj;} else if (obj instanceof Map) { //对于Map数据结构(for of循环 map.set(key,val))const newObj = new Map();map.set(obj, newObj);for (let [key, val] of obj) {newObj.set(key, deepClone(val, map));}return newObj;} else if (obj instanceof Array) { //对于数组数据结构(使用forEach进行循环push进行添加)const newObj = [];map.set(obj, newObj);obj.forEach(item => {newObj.push(deepClone(newObj[item], map));});return newObj} else if (obj instanceof Object) {const newObj = {};map.set(obj, newObj); //此处设置后,后面newObj即使更改,map内存地址使用的是一个所以map的值也会跟着变for (let key in obj) {newObj[key] = deepClone(obj[key], map);}// 注意是最后return不是在for循环中returnnewObj[key]return newObj;} else {return obj;}}// 循环引入var obj3 = {};obj3.a = obj3;var obj4 = deepClone(obj3);obj4.b = obj4;console.log(obj3 === obj4);console.log(obj3, obj4);
相关文章:

js深拷贝与浅拷贝
1.浅拷贝概念 浅拷贝是其属性与拷贝源对象的属性共享相同引用,当你更改源或副本时,也可能(可能说的是只针对引用数据类型)导致其他对象也发生更改。 特性: 会新创建一个对象,即objobj2返回fasle…...

Docker-harbor私有仓库部署与管理
搭建本地私有仓库 #首先下载 registry 镜像 docker pull registry #在 daemon.json 文件中添加私有镜像仓库地址 vim /etc/docker/daemon.json { "insecure-registries": ["20.0.0.50:5000"], #添加,注意用逗号结…...

ArcGIS笔记8_测量得到的距离单位不是米?一经度一纬度换算为多少米?
本文目录 前言Step 1 遇到测量结果以度为单位的情况Step 2 简单的笨办法转换为以米为单位Step 3 拓展:一经度一纬度换算为多少米 前言 有时我们会遇到这种情况,想在ArcGIS中使用测量工具测量一下某一段距离,但显示的测量结果却是某某度&…...

SpringBoot入门详解
目录 因何而生的SpringBoot 单体架构的捉襟见肘 SpringBoot的优点 快速入门 高曝光率的Annotation SpringBoot的工作机制 了解SpringBootApplication SpringBootConfiguration EnableAutoConfiguration 自动配置的幕后英雄:SpringFactoriesLoader Compon…...

数据分析案例-基于snownlp模型的MatePad11产品用户评论情感分析(文末送书)
🤵♂️ 个人主页:艾派森的个人主页 ✍🏻作者简介:Python学习者 🐋 希望大家多多支持,我们一起进步!😄 如果文章对你有帮助的话, 欢迎评论 💬点赞Ǵ…...

Leetcode刷题解析——904. 水果成篮
1. 题目链接:904. 水果成篮 2. 题目描述: 你正在探访一家农场,农场从左到右种植了一排果树。这些树用一个整数数组 fruits 表示,其中 fruits[i] 是第 i 棵树上的水果 种类 。 你想要尽可能多地收集水果。然而,农场的主…...
Spring Boot RESTful API
学习到接口部分了,记录一下 关于restful api感觉这篇文章讲的十分详细且通俗易懂一文搞懂什么是RESTful API - 知乎 (zhihu.com) Spring Boot 提供的 spring-boot-starter-web 组件完全支持开发 RESTful API ,提供了 GetMapping:处理get请求…...
k8s day04
昨日内容回顾: - configMap ---> cm 应用场景: 主要用于配置文件的持久化。 - secret 应用场景: 存储敏感数据,并非加密数据。 - pod探针(probe): - livenessProbe: 健康检查探针&#x…...

ESP32-IPS彩屏ST7789-Arduino-简单驱动
目的: 使ESP32能够驱动点亮ST7789显示屏 前提条件: ESP32 ST7789 (240 x240,IPS) 杜邦线 Arduino 过程: 0x00--接线 0x01--驱动: 彩屏驱动库 针对不同的彩屏驱动芯片,常用的 Arduino…...
高效工具类软件使用
高效工具类软件使用 目录概述需求: 设计思路实现思路分析1.Leanote2.Obsidian 的使用 参考资料和推荐阅读 Survive by day and develop by night. talk for import biz , show your perfect code,full busy,skip hardness,make a better result,wait for…...
批处理文件(.bat)中,dir与tree命令的效果
目录 dir命令 用法 操作 效果 dir /? dir dir D:\111\111_3 dir D:\111 *.mp4 dir D:\111 /ad dir D:\111 /ar dir D:\111 /s dir D:\111\111_3 >1bat.txt dir D:\111 >>1bat.txt tree命令 用法 操作 效果 tree /? tree tree D:\111\111_3 tree…...

STM32 ---- 再次学习STM32F103C8T6/STM32F409IGT6
目录 一、环境搭建及介绍 关于STM32基础介绍 新建工程 外设案例 LED流水灯 蜂鸣器 上拉电阻和下拉电阻知识 电压比较器 c语言基础知识 类型、结构体、枚举 类型int8_t int16_t int32_t 宏替换 #define 和typedef用法 结构体两种填充方法 和 命名规则 枚举用法 常用…...

UE4 EQS环境查询 学习笔记
EQS环境查询对应Actor的范围 EQS环境查询查询对应的类 查询到即有一个蓝色的球在Actor上,里面有位置信息等等 在行为树运行EQS,按键(‘)可以看到Player的位置已经被标记 运行对应的EQS在这里放如EQS就可以了 Generated Point&…...

计算机算法分析与设计(11)---贪心算法(活动安排问题和背包问题)
文章目录 一、贪心算法概述二、活动安排问题2.1 问题概述2.2 代码编写 三、背包问题3.1 问题描述3.2 代码编写 一、贪心算法概述 1. 贪心算法的定义:贪心算法是指在对问题求解时,总是做出在当前看来是最好的选择。也就是说,不从整体最优上加以…...

shell命令以及运行原理
Linux严格意义上说的是一个操作系统,我们称之为“核心(kernel)“ ,但我们一般用户,不能直接使用kernel。 而是通过kernel的“外壳”程序,也就是所谓的shell,来与kernel沟通。如何理解&a…...

MySQL进阶(再论JDBC)——JDBC编程思想的分析 JDBC的规范架构 JDBC相关的类分析
前言 SQL(Structured Query Language)是一种用于管理关系型数据库的标准化语言,它用于定义、操作和管理数据库中的数据。SQL是一种通用的语言,可以用于多种关系型数据库管理系统(RDBMS),如MySQ…...
rabbitMQ的知识点
RabbitMQ是一种消息队列软件,它实现了高度可靠的消息传递机制。RabbitMQ支持多种消息协议,包括AMQP、STOMP、MQTT等,比较灵活。以下是一些rabbitmq的知识点: 1. 消息队列:消息队列是一种分布式系统中广泛使用的通信模…...

EtherNet/IP 库卡机器人和EtherCAT倍福PLC总线协议连接案例
EtherNet/IP 是一种适合于工业环境和对时间要求比较苛刻的应用的网络。而远创智控YC-EIPM-ECT通讯网关,是一款自主研发的EtherNet/IP 从站功能的通讯网关。它不仅可以实现EtherNet/IP 和EtherCAT的无缝连接,还可以将EtherNet/IP 作为从站连接到EtherCAT总…...

微信小程序 uniapp+vue线上洗衣店业务管理系统演89iu2
本课题意在设计一种系统的、基于用户体验的线上洗衣服务模式,具有如下的研究意义: (1)为用户提供更简单、便捷的洗衣服务模式; (2)为智能柜的盈利模式提供了新的方向; (3)通过线上系统、智能柜与洗衣工厂结合的方式,为洗衣企业构建了一套节 省人力成本的…...
Maven项目,进行编译,使用idea的 编译功能,就是正常的,但是在终端中执行 mvn clean compile 报错
一、背景: Maven项目,进行编译,使用idea的 编译功能,就是正常的,但是在终端中执行 mvn clean compile 报错 报错信息: [ERROR] Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin…...

多模态2025:技术路线“神仙打架”,视频生成冲上云霄
文|魏琳华 编|王一粟 一场大会,聚集了中国多模态大模型的“半壁江山”。 智源大会2025为期两天的论坛中,汇集了学界、创业公司和大厂等三方的热门选手,关于多模态的集中讨论达到了前所未有的热度。其中,…...

智慧医疗能源事业线深度画像分析(上)
引言 医疗行业作为现代社会的关键基础设施,其能源消耗与环境影响正日益受到关注。随着全球"双碳"目标的推进和可持续发展理念的深入,智慧医疗能源事业线应运而生,致力于通过创新技术与管理方案,重构医疗领域的能源使用模式。这一事业线融合了能源管理、可持续发…...
【服务器压力测试】本地PC电脑作为服务器运行时出现卡顿和资源紧张(Windows/Linux)
要让本地PC电脑作为服务器运行时出现卡顿和资源紧张的情况,可以通过以下几种方式模拟或触发: 1. 增加CPU负载 运行大量计算密集型任务,例如: 使用多线程循环执行复杂计算(如数学运算、加密解密等)。运行图…...

k8s业务程序联调工具-KtConnect
概述 原理 工具作用是建立了一个从本地到集群的单向VPN,根据VPN原理,打通两个内网必然需要借助一个公共中继节点,ktconnect工具巧妙的利用k8s原生的portforward能力,简化了建立连接的过程,apiserver间接起到了中继节…...

【Oracle】分区表
个人主页:Guiat 归属专栏:Oracle 文章目录 1. 分区表基础概述1.1 分区表的概念与优势1.2 分区类型概览1.3 分区表的工作原理 2. 范围分区 (RANGE Partitioning)2.1 基础范围分区2.1.1 按日期范围分区2.1.2 按数值范围分区 2.2 间隔分区 (INTERVAL Partit…...
【碎碎念】宝可梦 Mesh GO : 基于MESH网络的口袋妖怪 宝可梦GO游戏自组网系统
目录 游戏说明《宝可梦 Mesh GO》 —— 局域宝可梦探索Pokmon GO 类游戏核心理念应用场景Mesh 特性 宝可梦玩法融合设计游戏构想要素1. 地图探索(基于物理空间 广播范围)2. 野生宝可梦生成与广播3. 对战系统4. 道具与通信5. 延伸玩法 安全性设计 技术选…...

Maven 概述、安装、配置、仓库、私服详解
目录 1、Maven 概述 1.1 Maven 的定义 1.2 Maven 解决的问题 1.3 Maven 的核心特性与优势 2、Maven 安装 2.1 下载 Maven 2.2 安装配置 Maven 2.3 测试安装 2.4 修改 Maven 本地仓库的默认路径 3、Maven 配置 3.1 配置本地仓库 3.2 配置 JDK 3.3 IDEA 配置本地 Ma…...

零基础在实践中学习网络安全-皮卡丘靶场(第九期-Unsafe Fileupload模块)(yakit方式)
本期内容并不是很难,相信大家会学的很愉快,当然对于有后端基础的朋友来说,本期内容更加容易了解,当然没有基础的也别担心,本期内容会详细解释有关内容 本期用到的软件:yakit(因为经过之前好多期…...
Redis的发布订阅模式与专业的 MQ(如 Kafka, RabbitMQ)相比,优缺点是什么?适用于哪些场景?
Redis 的发布订阅(Pub/Sub)模式与专业的 MQ(Message Queue)如 Kafka、RabbitMQ 进行比较,核心的权衡点在于:简单与速度 vs. 可靠与功能。 下面我们详细展开对比。 Redis Pub/Sub 的核心特点 它是一个发后…...

中医有效性探讨
文章目录 西医是如何发展到以生物化学为药理基础的现代医学?传统医学奠基期(远古 - 17 世纪)近代医学转型期(17 世纪 - 19 世纪末)现代医学成熟期(20世纪至今) 中医的源远流长和一脉相承远古至…...