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

let obj2 = obj1发生了什么?

JavaScript的数据类型:
什么是浅拷贝?
浅拷贝(shallow copy)创建的新对象拷贝的是原对象的属性的栈区地址。

图中同名变量的栈区地址相同,不同名变量的栈区地址不同。
a和_a、b和_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()相比于使用{},保持了原型链的继承。
缺陷:
- 不能处理循环引用,可能会导致堆栈溢出
- 对
Array、Date、RegExp、Map、Set对象的处理不好 - 不能拷贝不可枚举属性和
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.排序(…...
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 进行实现。 什么是希尔排序? 希尔排序,…...
新能源电动汽车安全性能检测中采集车架号及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 文件复制到 …...
AI应用开发利器:NeuroAPI网关统一管理多模型调用与部署实战
1. 项目概述:一个面向AI应用开发的API网关最近在折腾AI应用开发的朋友,估计都绕不开一个头疼的问题:模型管理。今天想试试Claude,明天项目需要接入GPT-4,后天可能又要调用一个开源的Llama模型。每个模型都有自己的API地…...
从ASCII到机器码:深入解析HEX文件的结构与校验机制
1. HEX文件的前世今生:从ASCII到机器码的桥梁 第一次接触HEX文件时,我也被那一串串看似毫无规律的十六进制字符搞得一头雾水。直到后来在嵌入式开发中频繁使用HEX文件进行固件升级,才真正理解了这个"翻译官"的重要性。HEX文件本质上…...
Python异步编程中的上下文管理:Ctxo工具的设计原理与实战应用
1. 项目概述:一个轻量级、高可用的上下文管理工具最近在折腾一个需要处理大量异步任务和复杂状态流转的后台服务,遇到了一个老生常谈但又很棘手的问题:如何在不同的函数调用、异步协程之间,安全、高效地传递和共享一些“上下文”信…...
OpenClaw Studio:基于Web技术的可视化自动化工作流构建平台解析
1. 项目概述:从开源仓库到创意工坊的蜕变 看到 grp06/openclaw-studio 这个项目标题,我的第一反应是:这又是一个在 GitHub 上诞生的、充满潜力的开源工具。 grp06 看起来像是一个团队或个人的标识,而 openclaw-studio 则直…...
3DMax对齐功能全解析:从基础操作到高阶建模实战
1. 3DMax对齐功能基础入门 刚接触3D建模的新手最常遇到的困扰就是:为什么我的模型总是对不齐?记得我第一次用3DMax做建筑模型时,花了两小时都没能把一扇窗户准确地装到墙面上。直到后来掌握了对齐工具,才发现原来这种问题5秒钟就能…...
UTF8-CPP跨版本兼容性指南:从C++98到C++20的完整支持
UTF8-CPP跨版本兼容性指南:从C98到C20的完整支持 【免费下载链接】utfcpp UTF-8 with C in a Portable Way 项目地址: https://gitcode.com/gh_mirrors/ut/utfcpp UTF8-CPP是一个轻量级的C库,专注于以可移植的方式提供UTF-8编码和解码功能&#x…...
Arduino智能小车避障与拟人化设计:从传感器到行为逻辑
1. 项目概述与核心思路最近在整理工作室的物料,翻出了几个闲置的360度舵机和超声波模块,手痒之下决定做个智能小车玩玩。这个项目本身不新鲜,网上教程一抓一大把,但我想做点不一样的:不仅要能实现基础的自动避障&#…...
猫眼启发的亚太赫兹超表面成像系统设计与应用
1. 猫眼启发的亚太赫兹超表面成像系统概述在电磁波成像技术领域,传统系统往往面临视场匹配困难、系统冗余度高以及实时性不足等挑战。受猫眼结构中反光膜(tapetum lucidum)的生物学启发,我们开发了一种创新的主动-被动复合孔径共享…...
【综合能源】电热冷综合能源优化调度研究(Matlab代码实现)
💥💥💞💞欢迎来到本博客❤️❤️💥💥 🏆博主优势:🌞🌞🌞博客内容尽量做到思维缜密,逻辑清晰,为了方便读者。 ⛳️座右铭&a…...
开源机械爪资源库指南:从入门到ROS集成与自主抓取
1. 项目概述:一个开源“机械爪”的宝藏资源库如果你对机器人、自动化或者DIY硬件感兴趣,最近又在琢磨着给自己的项目加一个“手”,那么你很可能已经听说过“机械爪”这个概念。无论是想做一个自动抓取小物件的桌面机器人,还是为你…...
