JS - 浅拷贝和深拷贝

目录

  • 1,概念
  • 2,浅拷贝
    • 1,直接赋值
    • 2,Object.assign()
    • 3,扩展运算符
    • 4,数组 slice() 和 concat()
    • 5,jquery 中的 $.extend()
    • 6,lodash.clone()
  • 3,深拷贝
    • 1,JSON.parse(JSON.stringify)
    • 2,structuredClone()
    • 3,jquery 中的 $.extend()
    • 4,lodash.cloneDeep()
  • 4,遇到的问题和使用建议
    • 遇到的问题
    • 使用建议
  • 5,手动递归简单实现深拷贝

1,概念

浅拷贝:只拷贝基本类型的数据,引用类型的数据拷贝后也会发生引用,因为拷贝的是对象的引用地址。

深拷贝:在堆中重新分配内存,并把源对象中所有属性都新建拷贝,新旧对象完全隔离,互不影响。

2,浅拷贝

1,直接赋值

const user = {name: '下雪天的夏风'
}const user2 = user
user.name = 'xxx'console.log(user); // { name: 'xxx' }
console.log(user2); // { name: 'xxx' }
console.log(user === user2); // true

2,Object.assign()

MDN 参考

const user = {name: "下雪天的夏风",address: {province: "陕西",city: "西安",},
};const user2 = Object.assign({}, user);
user2.name = "xxx";
user2.address.province = "北京";console.log(user); // { name: '下雪天的夏风', address: { province: '北京', city: '西安' } }
console.log(user2); // { name: 'xxx', address: { province: '北京', city: '西安' } }

3,扩展运算符

const user = {name: "下雪天的夏风",address: {province: "陕西",city: "西安",},
};const user2 = { ...user };
user2.name = "xxx";
user2.address.province = "北京";console.log(user); // { name: '下雪天的夏风', address: { province: '北京', city: '西安' } }
console.log(user2); // { name: 'xxx', address: { province: '北京', city: '西安' } }

4,数组 slice() 和 concat()

数组元素是引用类型时,同样拷贝的是引用地址。

const arr1 = [1, true, "Hello", { name: "下雪天的夏风", age: 18 }];
// slice() 替换为 concat() 结果一致。
const arr2 = arr1.slice();arr2[0] = 2;
arr2[3].age = 36;console.log(arr1); // [ 1, true, 'Hello', { name: '下雪天的夏风', age: 36 } ]
console.log(arr2); // [ 2, true, 'Hello', { name: '下雪天的夏风', age: 36 } ]

5,jquery 中的 $.extend()

jQuery 中,$.extend([deep], target, object1, [objectN]) 方法可进行深浅拷贝。jquery 中文文档

  • deep:true 为深拷贝,默认为 false 浅拷贝
  • target:目标对象
  • object1:待拷贝到第一个源对象
  • objectN:待拷贝到第N个源对象
<script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.7.1/jquery.min.js"></script>
<script>const user = {name: "下雪天的夏风",address: {province: "陕西",city: "西安",},};const user2 = {};$.extend(user2, user);user2.name = "xxx";user2.address.province = "北京";console.log(user); // { name: '下雪天的夏风', address: { province: '北京', city: '西安' } }console.log(user2); // { name: 'xxx', address: { province: '北京', city: '西安' } }
</script>

6,lodash.clone()

loadsh 中文文档

<script src="https://cdn.bootcdn.net/ajax/libs/lodash.js/4.17.21/lodash.min.js"></script>
<script>const user = {name: "下雪天的夏风",address: {province: "陕西",city: "西安",},};const user2 = _.clone(user);user2.name = "xxx";user2.address.province = "北京";console.log(user); // { name: '下雪天的夏风', address: { province: '北京', city: '西安' } }console.log(user2); // { name: 'xxx', address: { province: '北京', city: '西安' } }
</script>

3,深拷贝

遇到的问题和使用建议后面会介绍。

1,JSON.parse(JSON.stringify)

const user = {name: "下雪天的夏风",address: {province: "陕西",city: "西安",},
};const user2 = JSON.parse(JSON.stringify(user));user2.name = "xxx";
user2.address.province = "北京";console.log(user); // { name: '下雪天的夏风', address: { province: '陕西', city: '西安' } }
console.log(user2); // { name: 'xxx', address: { province: '北京', city: '西安' } }

2,structuredClone()

全局属性。浏览器环境是 window 的属性,node 环境是 global 的属性。

const user = {name: "下雪天的夏风",address: {province: "陕西",city: "西安",},
};const user2 = structuredClone(user);user2.name = "xxx";
user2.address.province = "北京";console.log(user); // { name: '下雪天的夏风', address: { province: '陕西', city: '西安' } }
console.log(user2); // { name: 'xxx', address: { province: '北京', city: '西安' } }

3,jquery 中的 $.extend()

<script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.7.1/jquery.min.js"></script>
<script>const user = {name: "下雪天的夏风",address: {province: "陕西",city: "西安",},};const user2 = {};$.extend(true, user2, user);user2.name = "xxx";user2.address.province = "北京";console.log(user); // { name: '下雪天的夏风', address: { province: '陕西', city: '西安' } }console.log(user2); // { name: 'xxx', address: { province: '北京', city: '西安' } }
</script>

4,lodash.cloneDeep()

<script src="https://cdn.bootcdn.net/ajax/libs/lodash.js/4.17.21/lodash.min.js"></script>
<script>const user = {name: "下雪天的夏风",address: {province: "陕西",city: "西安",},};const user2 = _.cloneDeep(user);user2.name = "xxx";user2.address.province = "北京";console.log(user); // { name: '下雪天的夏风', address: { province: '陕西', city: '西安' } }console.log(user2); // { name: 'xxx', address: { province: '北京', city: '西安' } }
</script>

4,遇到的问题和使用建议

遇到的问题

可以看到,上面的例子中使用的都是简单的基本数据类型和普通对象,这也是日常开发中最常见的。

但还有一些特殊情况,比如函数在进行深拷贝时,其实和基本类型一样直接拷贝即可。但函数不支持序列化和结构化算法!所以 JSON.parse(JSON.stringify)structuredClone() 无法处理函数,所以源对象中有函数时会有问题!

const user = {getAge() {console.log(18);},
};const user2 = JSON.parse(JSON.stringify(user));
console.log(user2); // {},函数直接被忽略
const user = {getAge() {console.log(18);},
};// 结构化算法无法处理函数。
// Uncaught DOMException: Failed to execute 'structuredClone' on 'Window': getAge() 
const user2 = window.structuredClone(user);

还有一些特殊的对象,比如日期对象,正则对象,包装类型,Map,Set 等,在拷贝时都需要特殊处理。

使用建议

在生成环境中的建议:

  • 如果只是简单的数据类型,比如基本类型和普通对象,用哪种方法都无所谓。
  • 如果有复杂的类型,建议使用 lodash.cloneDeep()$.extend()

5,手动递归简单实现深拷贝

特殊的类型就不考虑了,主要是完善下 JSON.parse(JSON.stringify) 不支持函数的拷贝。Map 和 Set 其实也是判断后遍历递归即可。

function deepClone(target) {let result;// 基本类型、函数,直接赋值。if (typeof target !== "object" || typeof target === null) {result = target;} else {result = Array.isArray(target) ? [] : {};for (const key in target) {result[key] = deepClone(target[key]);}}return result;
}

以上。

参考-如何实现深拷贝

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

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

相关文章

Java数据类型相关

数据类型 Java有哪些数据类型 定义&#xff1a;Java语言是强类型语言&#xff0c;对于每一种数据都定义了明确的具体的数据类 型&#xff0c;在内存中分配了不同大小的内存空间。 分类&#xff1a; 基本数据类型 数值型 整数类型(byte,short,int,long) 浮点类型(float,dou…

【数据结构】模式匹配之KMP算法与Bug日志—C/C++实现

​&#x1f308;个人主页&#xff1a;Sarapines Programmer&#x1f525; 系列专栏&#xff1a;《数据结构奇遇记》&#x1f516;墨香寄清辞&#xff1a;墨痕寄壮志&#xff0c;星辰梦未满。 通幽径心凝意&#xff0c;剑指苍穹势如山。 目录 &#x1f31e;1. 模式匹配的基本概念…

Spring Boot之自定义starter

&#x1f973;&#x1f973;Welcome Huihuis Code World ! !&#x1f973;&#x1f973; 接下来看看由辉辉所写的关于Spring Boot的相关操作吧 目录 &#x1f973;&#x1f973;Welcome Huihuis Code World ! !&#x1f973;&#x1f973; 一. starter是什么 二.为什么要使…

计算机操作系统-第十六天

目录 线程的实现方式 用户级线程 内核级线程 多线程模型 一对一模型 多对多模型 多对多模型 本节思维导图 线程的实现方式 用户级线程 历史背景&#xff1a;早期操作系统只支持进程&#xff0c;不支持线程&#xff0c;当时的线程是由线程库实现的 本质&#xff1a;从…

【普中】基于51单片机简易计算器显示设计( proteus仿真+程序+设计报告+实物演示+讲解视频)

目录标题 &#x1f4df;1. 主要功能&#xff1a;&#x1f4df;2. 讲解视频&#xff1a;&#x1f4df;3. 设计说明书(报告)&#x1f4df;4. 仿真&#x1f4df;5. 实物烧录和现象&#x1f4df;6. 程序代码&#x1f4df;7. 设计资料内容清单 【普中开发板】基于51单片机简易计算器…

二叉树中的中序遍历、反向遍历和逆序

概念 中序遍历&#xff08;Inorder Traversal&#xff09;&#xff1a; 中序遍历是二叉树遍历的一种方式&#xff0c;它的顺序是左子树、根节点、右子树。对于一个二叉搜索树&#xff08;BST&#xff09;&#xff0c;中序遍历可以得到一个升序的节点序列。中序遍历的步骤是首先…

深度学习之模型权重

在深度学习中&#xff0c;模型的权重&#xff08;weights&#xff09;是指神经网络中的参数&#xff0c;这些参数用于调整和学习模型的行为&#xff0c;以便能够对输入数据进行有效的映射和提取有用的特征。深度学习模型通常由许多神经元和连接组成&#xff0c;而权重就是连接这…

processon使用及流程图和泳道图的绘画(登录界面流程图,门诊流程图绘制门诊泳道图,住院泳道图,OA会议泳道图),Axure自定义元件

目录 一.processon图形的使用场景介绍 二.流程图绘画 三.泳道图的绘画 1.绘制门诊流程图绘制门诊泳道图 2. 绘制住院泳道图​编辑 3.绘制药库采购入库流程图 4.绘制OA会议泳道图 四.Axure自定义元件 1.Axure载入元件库 一.processon图形的使用场景介绍 二.流程图绘画 示例&…

数字图像处理 - 使用Rembg库在Python中轻松删除背景

Python 中的 rembg 模块是一个用于去除图像背景的库。它基于Rembg算法,采用神经网络来执行背景去除任务。该算法经过训练,可以识别图像中的前景物体并将其与背景分开,从而产生具有透明背景的图像。 rembg库基于Rembg算法,该算法本身有一个有趣的历史。Rembg算法由研究员兼软…

鸿蒙开发组件之Web

一、加载一个url myWebController: WebviewController new webview.WebviewControllerbuild() {Column() {Web({src: https://www.baidu.com,controller: this.myWebController})}.width(100%).height(100%)} 二、注意点 2.1 不能用Previewer预览 Web这个组件不能使用预览…

C/C++函数调用栈信息输出(backtrace backtrace_symbols)

C/C函数调用栈信息输出&#xff08;backtrace & backtrace_symbols&#xff09; 最近工作&#xff0c;搞了一个死锁问题&#xff0c;加了好多输出无法定位问题。 就想着在锁操作调用的地方输出函数调用栈信息&#xff0c;试了一下&#xff0c;竟然实现了。 源代码 #incl…

《PCL多线程加速处理》-配准-icp

《PCL多线程加速处理》-配准-icp 一、效果展示二、具体实现三、代码一、效果展示 数据越大,速度提升效果越快 1、48万点 2、十万点 3、三万点 4、9000点 配准数据 二、具体实现

构建智能外卖跑腿小程序:技术实践与代码示例

在快节奏的现代生活中&#xff0c;外卖跑腿服务已成为人们日常生活中不可或缺的一部分。为了提供更智能、高效的外卖跑腿体验&#xff0c;本文将深入探讨构建一款智能外卖跑腿小程序所需的关键技术&#xff0c;并提供相应的代码示例。 1. 地理位置服务的整合 外卖跑腿小程序…

小程序 -网络请求post/get

1.1网络请求的概念(post和get) 1.2步骤 1.3 应用函数 js里面写&#xff0c;用bindtap绑在控件上&#xff0c;就不讲了 实例代码&#xff1a; //发起get数据请求get_info(){wx.request({url:https://www.escook.cn/api/get,//请求的接口地址,必须基于https协议//请求的方式met…

ElasticSearch之Shard request cache settings

对于查询操作&#xff0c;Elasticsearch提供了缓存特性来暂存结果。 对于相同条件的查询请求&#xff0c;在缓存中的数据失效前&#xff0c;响应后续的查询操作时可以直接从缓存中提取结果&#xff0c;有效降低检索操作的时延&#xff0c;提升检索数据时的体验。 提到缓存相关的…

SpringBoot项目打成War包部署

简介 一般情况下&#xff0c;在SpringBoot项目开发完成进行服务器部署时&#xff0c;都是打成JAR包进行部署运行的。但是在有些情况下也需要将其打成War包使用Tomcat进行部署。本篇文章就简单介绍一下SpringBoot如何打成War包。 注意&#xff1a; 测试Demo的SpringBoot版本为2…

python selenium chrome114版本之后环境配置和携带缓存打开chrome

尽力局 chrome驱动环境配置chrome打开带缓存设置待缓存打开自动关闭浏览器自动关闭浏览器弹窗 最终代码找资料难啊最终效果代码 依赖包和生成依赖包方法关闭谷歌升级 chrome驱动环境配置 网上找到的资料&#xff0c;我现在安装的是120版本的&#xff0c;这个资料是可行的。比较…

Jetbrains IDEA 2023.3 更新

本心、输入输出、结果 文章目录 Jetbrains IDEA 2023.3 更新前言Jetbrains IDEA 2023.3 主要更新内容功能更新用户体验优化数据库工具花有重开日,人无再少年实践是检验真理的唯一标准Jetbrains IDEA 2023.3 更新 编辑:简简单单 Online zuozuo 地址:https://blog.csdn.net/qq…

mysql分页查询性能测试

测试环境&#xff1a;1.1亿数据&#xff0c;约22GB大小&#xff0c;6核12线程32GBmysql8,ssd硬盘 表为常见的订单表&#xff0c;表中26个字段。 网上传说limit不同的使用方式对性能影响很大&#xff0c;自己也有点好奇&#xff0c;于是直接做个测试。 下面直接展示mysql在进…

【数据库设计和SQL基础语法】--查询数据--排序

一、排序数据 1.1 ORDER BY子句 单列排序 单列排序是通过使用 ORDER BY 子句对查询结果按照单个列进行排序。以下是单列排序的一些示例&#xff1a; 升序排序&#xff08;默认&#xff09;&#xff1a; SELECT column1, column2, ... FROM your_table_name ORDER BY column_t…