当前位置: 首页 > news >正文

【JavaScript】浅拷贝与深拷贝

引言

浅拷贝、深拷贝是对引用类型而言的。

引用类型的变量对应一个栈区地址,这个栈区地址处存储的值是存放的真正的数据的堆区地址。

基本数据类型的变量也对应一个栈区地址,但是该地址存储的是其真正的值。

let a = b发生了什么?

在这里插入图片描述

let obj2 = obj1发生了什么?

在这里插入图片描述

JavaScript的数据类型:

什么是浅拷贝?

浅拷贝(shallow copy)创建的新对象拷贝的是原对象的属性的栈区地址。

在这里插入图片描述

图中同名变量的栈区地址相同,不同名变量的栈区地址不同。

a_ab_b都是复制了原来栈区地址的值,对_a的修改不会影响a,对_b的修改却会影响b,因为它们相当于let _b = b的关系。

什么是深拷贝?

深拷贝(deep copy)拷贝对象的堆区数据为新副本,如此新旧对象不会互相影响。

在这里插入图片描述

浅拷贝的方法有哪些?

1.JavaScript中对象的合并,Object.assign本身是浅拷贝。

const originalObject = {a:1,b:{c:1}}
const shallowCopy = Object.assign({}, originalObject);
console.log(shallowCopy === originalObject);//false,比较的是栈区地址
shallowCopy.a = 2;
shallowCopy.b.c = 2;
console.log(originalObject.a);// 1
console.log(originalObject.b.c);// 2

缺陷:Object.assign不会拷贝继承属性、不可枚举属性。

2.展开语法

let newObj = {...obj}

3.数组的cancat方法

const newArr = oldArr.concat([])

4.数组的slice方法

const newArr = oldArr.slice(start[,end]);

5.浅拷贝细致点看,是先创建一个新对象,然后将原对象的属性直接复制到新对象,所以也可以自己写一个浅拷贝函数:

function shallowCopy(obj) {if(obj === null || typeof obj !== 'object') return obj;const newObj = {};for (let key in obj) {// 会遍历原型链上的可枚举属性obj.hasOwnProperty(key) && (newObj[key] = obj[key]);}return newObj;
}
// Object.prototype.d = 1;
const obj1 = { a: 1, b: { c: 1 } };
const obj2 = shallowCopy(obj1);
obj2.a = 2;
obj2.b.c = 2;

也可以不用每次判断是否是自有属性:

function shallowCopy(obj) {if(obj === null || typeof obj !== 'object') return obj;const newObj = {};Object.getOwnPropertyNames(obj).forEach(key=>{newObj[key] = obj[key];})return newObj;
}

6.lodash库的浅拷贝方法

如何实现深拷贝?

1.JSON.stringify()JSON.parse()

function deepClone(obj){if(obj === null || typeof obj !== 'object') return obj;return JSON.parse(JSON.stringify(obj));
}

缺陷:

  • 丢失function、undefined、Symbol这几种类型的键值对
  • NaN、Infinity的值会转为null
  • Date会变为字符串
  • RegExp会变成空对象
  • 不能拷贝不可枚举属性及原型链上的属性
  • 不能解决循环引用

2.lodash库的深拷贝方法

3.手动实现深拷贝函数基础版:

function deepClone(obj) {if(obj === null || typeof obj !== 'object') return obj;const newObj = new obj.constructor();for (let key in obj) {if (obj.hasOwnProperty(key)){newObj[key] = typeof obj[key] === "object" ? arguments.callee(obj[key]) : obj[key];}}return newObj;
}

const newObj = new obj.constructor()相比于使用{},保持了原型链的继承。

缺陷:

  • 不能处理循环引用,可能会导致堆栈溢出
  • ArrayDateRegExpMapSet对象的处理不好
  • 不能拷贝不可枚举属性和Symbol类型属性

4.手动实现深拷贝函数进阶版:

//判断是否为复杂数据类型
const isComplexDataType = obj => (typeof obj === 'object' || typeof obj === 'function') && (obj !== null);const deepClone = function(obj,hash = new WeakMap()){if(hash.has(obj)) return hash.get(obj);//如果参数为Date, RegExp, Set, Map, WeakMap, WeakSet等引用类型,则直接生成一个新的实例let type = [Date,RegExp,Set,Map,WeakMap,WeakSet];if(type.includes(obj.constructor)) return new obj.constructor(obj);//遍历传入参数所有属性描述符let allDesc = Object.getOwnPropertyDescriptors(obj);//继承原型let cloneObj = Object.create(Object.getPrototypeOf(obj),allDesc);// 获取所有 Symbol 类型键let symKeys = Object.getOwnPropertySymbols(obj);// 拷贝 Symbol 类型键对应的属性if (symKeys.length > 0) {symKeys.forEach(symKey => {cloneObj[symKey] = isComplexDataType(obj[symKey]) ? deepClone(obj[symKey], hash) : obj[symKey]})}// 哈希表设值hash.set(obj,cloneObj);//Reflect.ownKeys(obj)拷贝不可枚举属性和符号类型for(let key of Reflect.ownKeys(obj)){// 如果值是引用类型并且非函数则递归调用deepClonecloneObj[key] =(isComplexDataType(obj[key]) && typeof obj[key] !== 'function') ? deepClone(obj[key],hash) : obj[key];}return cloneObj;
};

参考资料:

  • JavaScript中浅拷贝和深拷贝的区别与实现
  • JavaScript深拷贝和浅拷贝看这篇就够了
  • 关于堆栈的讲解(我见过的最经典的)
  • 深入理解js数据类型与堆栈内存
  • js中深浅拷贝的实现方式(含图解原理)
  • JavaScript深拷贝看这篇就行了!(实现完美的ES6+版本)
  • 【JavaScript】arguments.callee的作用及替换方案
  • [javascript核心-15] 手写完美深拷贝代码实现🍌
  • JS中JSON序列化JSON.stringify的坑点和处理

相关文章:

【JavaScript】浅拷贝与深拷贝

引言 浅拷贝、深拷贝是对引用类型而言的。 引用类型的变量对应一个栈区地址,这个栈区地址处存储的值是存放的真正的数据的堆区地址。 基本数据类型的变量也对应一个栈区地址,但是该地址存储的是其真正的值。 let a b发生了什么? let obj…...

如何下载IEEE Journal/Conference/Magazine的LaTeX/Word模板

当你准备撰写一篇学术论文或会议论文时,使用IEEE(电气和电子工程师协会)的LaTeX或Word模板是一种非常有效的方式,它可以帮助你确保你的文稿符合IEEE出版的要求。无论你是一名研究生生或一名资深学者,本教程将向你介绍如…...

nvidia 驱动问题

https://stackoverflow.com/questions/43022843/nvidia-nvml-driver-library-version-mismatch https://zhuanlan.zhihu.com/p/643773939...

PDF编辑和OCR文字识别工具ABBYY FineReader PDF

ABBYY FineReader PDF是一款专业的OCR文字识别和PDF编辑工具,可以帮助用户更好地处理和管理PDF文档。以下是ABBYY FineReader PDF的一些特点: 1. 文字识别精准:ABBYY FineReader PDF具有强大的OCR文字识别功能,可以将PDF中的文字…...

什么是网络流量监控

随着许多服务迁移到云,网络基础架构的维护变得复杂。虽然云采用在生产力方面是有利的,但它也可能让位于未经授权的访问,使 IT 系统容易受到安全攻击。 为了确保其网络的安全性和平稳的性能,IT 管理员需要监控用户访问的每个链接以…...

ubuntu 终端 中文显示unicode码、乱码

Ubuntu默认的中文字符编码 locale命令查看 LANG 等参数是否无UTF-8等参数?比如 为空? Ubuntu默认的中文字符编码为zh_CN.UTF-8,这个可以在 /etc/environment中看到: sudo gedit /etc/environment 可以看到如下内容: P…...

作用域理解

概念:它是指对某一变量和方法具有访问权限的代码空间, 在JS中, 作用域是在函数中维护的。表示变量 或函数起作用的区域,指代了它们在什么样的上下文中执行,亦即上下文执行环境。 ES5的作用域只有两种:全局作用域和局部作用域 全局作用域 var a1; //全局作用域 function fn1(…...

Stream 流式编程创建及其常用操作方法

目录 Stream 对象如何创建 Stream 常用的操作方法 1.过滤(Filter) 2.映射(Map) 3.扁平映射(FlatMap) 4.截断(Limit) 5.跳过(Skip) 6.排序&#xff08…...

Can 通信-协议

概述 CAN 是 Controller Area Network 的缩写(以下称为 CAN),是 ISO国际标准化的串行通信协议。 在当前的汽车产业中,出于对安全性、舒适性、方便性、低公害、低成本的要求,各种各样的电子控制系统 被开发了出来。由于…...

rustlings本地开发环境配置

克隆自己的仓库 首先我们要在github上找到自己仓库并把它克隆到本地 git clone https://github.com/LearningOS/rust-rustlings-2023-autumn-******.git下载插件 rust-analyzer和Git Graph一个可以用来解析rust代码,另一个可以可视化管理git代码库 下载rustling…...

希尔排序:优化插入排序的精妙算法

排序算法在计算机科学中扮演着重要的角色,其中希尔排序(Shell Sort)是一种经典的排序算法。本文将带您深入了解希尔排序,包括其工作原理、性能分析以及如何使用 Java 进行实现。 什么是希尔排序? 希尔排序&#xff0c…...

新能源电动汽车安全性能检测中采集车架号及BMS电池数据的难点

按照新能源电动汽车安全性能检测,必须采集到汽车的车架号及BMS电池数据做对应的评测。国内电动汽车主要以比亚迪、特斯拉、广汽埃安、五菱新能源、长安新能源、大众、理想、蔚来、哪吒等主流为主。与传统燃油车不同的是,电动汽车不用执行OBD2标准&#x…...

函数reshape(-1,)里的-1的意思

reshape函数是对narray的数据结构进行维度变换,由于变换遵循对象元素个数不变,在进行变换时,假设一个数据对象narray的总元素个数为N,如果我们给出一个维度为(m,-1)时,我们就理解为将…...

名词作形容词的用法

【名词作形容词的用法】 有考英语二的同学问我,为什么名词能修饰名词,比如spending proportion(支出比例), job satisfaction(工作满意度),之前老师不是说这种写法不能乱用么? 那我在这里简单说明一下“形…...

若依微服务部署,裸服务部署、docker部署、k8s部署

目录 前言windows 部署若依-微服务版本浏览器验证docker部署若依-微服务版本浏览器验证k8s部署若依-微服务版本浏览器验证总结 前言 环境:centos7、Win10 若依是一个合适新手部署练习的开源的微服务项目,本篇讲解Windows部署若依微服务、docker部署若依…...

【置顶】关于博客的一些公告

所谓 万事开头难,最开始的两个专栏 《微机》 和 《骨骼动作识别》 定价 29.9 ,因为: 刚开始确实比较困难,要把自己学的知识彻底搞懂讲给别人,还要 码字排版,从 Markdown 语法开始学起(这都是 花…...

Fastadmin后端表格动态展示列

前言 后端有多角色时, 往往有些表格中的列需要根据条件来根据角色身份决定是不是需要该角色查看, 为此就衍生出一个需要动态控制展示某列的需求fastadmin框架内调用的table实际上在初始化时, 可以修改columns中的visible属性来控制是否显示, 但是这个参数只能传入bool, 不能像…...

如何在ubnutu上安装docker

卸载旧版本 sudo apt-get remove docker docker-engine docker.io添加HTTPS传输软件包以及CA证书 sudo apt-get update sudo apt-get install \apt-transport-https \ca-certificates \curl \gnupg \lsb-release添加国内源以提升网速 添加软件源的GPG秘钥以确认所下载软件包…...

Mall脚手架总结(三) —— MongoDB存储浏览数据

前言 通过Elasticsearch整合章节的学习,我们了解SpringData框架以及相应的衍生查询的方式操作数据读写的语法。MongoDB的相关操作也同样是借助Spring Data框架,因此这篇文章的内容比较简单,重点还是弄清楚MongoDB的使用场景以及如何通过Sprin…...

Maven 引入外部依赖

如果我们需要引入第三方库文件到项目,该怎么操作呢? pom.xml 的 dependencies 列表列出了我们的项目需要构建的所有外部依赖项。 要添加依赖项,我们一般是先在 src 文件夹下添加 lib 文件夹,然后将你工程需要的 jar 文件复制到 …...

XML Group端口详解

在XML数据映射过程中,经常需要对数据进行分组聚合操作。例如,当处理包含多个物料明细的XML文件时,可能需要将相同物料号的明细归为一组,或对相同物料号的数量进行求和计算。传统实现方式通常需要编写脚本代码,增加了开…...

业务系统对接大模型的基础方案:架构设计与关键步骤

业务系统对接大模型:架构设计与关键步骤 在当今数字化转型的浪潮中,大语言模型(LLM)已成为企业提升业务效率和创新能力的关键技术之一。将大模型集成到业务系统中,不仅可以优化用户体验,还能为业务决策提供…...

Mybatis逆向工程,动态创建实体类、条件扩展类、Mapper接口、Mapper.xml映射文件

今天呢,博主的学习进度也是步入了Java Mybatis 框架,目前正在逐步杨帆旗航。 那么接下来就给大家出一期有关 Mybatis 逆向工程的教学,希望能对大家有所帮助,也特别欢迎大家指点不足之处,小生很乐意接受正确的建议&…...

pam_env.so模块配置解析

在PAM(Pluggable Authentication Modules)配置中, /etc/pam.d/su 文件相关配置含义如下: 配置解析 auth required pam_env.so1. 字段分解 字段值说明模块类型auth认证类模块,负责验证用户身份&am…...

智能在线客服平台:数字化时代企业连接用户的 AI 中枢

随着互联网技术的飞速发展,消费者期望能够随时随地与企业进行交流。在线客服平台作为连接企业与客户的重要桥梁,不仅优化了客户体验,还提升了企业的服务效率和市场竞争力。本文将探讨在线客服平台的重要性、技术进展、实际应用,并…...

OkHttp 中实现断点续传 demo

在 OkHttp 中实现断点续传主要通过以下步骤完成,核心是利用 HTTP 协议的 Range 请求头指定下载范围: 实现原理 Range 请求头:向服务器请求文件的特定字节范围(如 Range: bytes1024-) 本地文件记录:保存已…...

【论文笔记】若干矿井粉尘检测算法概述

总的来说,传统机器学习、传统机器学习与深度学习的结合、LSTM等算法所需要的数据集来源于矿井传感器测量的粉尘浓度,通过建立回归模型来预测未来矿井的粉尘浓度。传统机器学习算法性能易受数据中极端值的影响。YOLO等计算机视觉算法所需要的数据集来源于…...

三体问题详解

从物理学角度,三体问题之所以不稳定,是因为三个天体在万有引力作用下相互作用,形成一个非线性耦合系统。我们可以从牛顿经典力学出发,列出具体的运动方程,并说明为何这个系统本质上是混沌的,无法得到一般解…...

Device Mapper 机制

Device Mapper 机制详解 Device Mapper(简称 DM)是 Linux 内核中的一套通用块设备映射框架,为 LVM、加密磁盘、RAID 等提供底层支持。本文将详细介绍 Device Mapper 的原理、实现、内核配置、常用工具、操作测试流程,并配以详细的…...

如何更改默认 Crontab 编辑器 ?

在 Linux 领域中,crontab 是您可能经常遇到的一个术语。这个实用程序在类 unix 操作系统上可用,用于调度在预定义时间和间隔自动执行的任务。这对管理员和高级用户非常有益,允许他们自动执行各种系统任务。 编辑 Crontab 文件通常使用文本编…...