JS - js中常用的深拷贝和浅拷贝理解

news/2024/4/25 9:04:49/文章来源:https://blog.csdn.net/qq_43886365/article/details/129255034

文章目录

    • 1,JS数据类型
    • 2,深浅拷贝概念
    • 3,浅拷贝实现
    • 4,深拷贝实现

1,JS数据类型

基本数据类型

Number、Boolean、String、undefined、Null。变量是直接按值存放的,存放在栈内存中的简单数据段,可以直接访问。

复杂数据类型(也叫引用类型):

Function、Array、Objec等(typeof()这个三种类型得到的都是object)是存放在堆内存中的对象,变量保存的是一个指针,这个指针指向另一个位置。当需要访问引用类型的值时,首先从栈中获得该对象的地址指针,然后再从堆内存中取得所需的数据。

基本类型都放在栈(图左)(stack)里
引用类型都放在堆(图右)(heap)里
在这里插入图片描述

2,深浅拷贝概念

浅拷贝:只拷贝值的引用,不拷贝内存;对源或副本的更改可能也会导致其他对象的更改;

深拷贝:既拷贝值又拷贝内存;改动副本的数据不会对原数据产生影响;

MDN上描述如下:
在这里插入图片描述

3,浅拷贝实现

1,Object.assign()

Object.assign():用于对象的合并,将源对象的所有可枚举属性,复制到目标对象,并返回合并后的target;用法: Object.assign(target, source1, source2);
注意:Object.assign 方法只会拷贝源对象 可枚举的 和 自身的 属性到目标对象;(继承的属性和原型链上面的属性以及不可枚举的属性是不会进行复制的)

1.1,基本使用:

const obj = { a: 1 };
const copy = Object.assign({}, obj);
console.log(copy); // { a: 1 }let obj1 = { a: 0 , b: { c: 0}};
let obj2 = Object.assign({}, obj1);
console.log(JSON.stringify(obj2)); // { "a": 0, "b": { "c": 0}}

1.2,assign()还可以合并具有相同属性的对象:

属性会被后续参数中具有相同属性的其他对象覆盖。

const o1 = { a: 1, b: 1, c: 1 };
const o2 = { b: 2, c: 2 };
const o3 = { c: 3 };const obj = Object.assign({}, o1, o2, o3);
console.log(obj); // { a: 1, b: 2, c: 3 } 属性会被后续参数中具有相同属性的其他对象覆盖。

1.3,assign()还会把基本类型包装为对象:

基本数据类型将被包装,null和undefined将被忽略。

// 基本数据类型
const v1 = 'abc';
const v2 = true;
const v3 = 10;
const v4 = Symbol('foo');const obj1 = Object.assign({}, v1, null, v2, undefined, v3, v4);
// 基本数据类型将被包装,null和undefined将被忽略。
console.log(obj1); 

2,slice()

slice() 方法返回一个新的数组对象,这一对象是一个由 begin 和 end 决定的原数组的浅拷贝(包括 begin,不包括end)。原始数组不会被改变。

2.1,基本用法

const animals = ['ant', 'bison', 'camel', 'duck', 'elephant'];
## 传一个值时表示从0开始
console.log(animals.slice(2));
// 输出结果: ["camel", "duck", "elephant"]## 包括开始,不包括结尾
console.log(animals.slice(1, 5));
// 输出结果: ["bison", "camel", "duck", "elephant"]## 什么都不传返回原数组:
console.log(animals.slice());
// 输出结果: ["ant", "bison", "camel", "duck", "elephant"]## 负值表示从末尾开始查
console.log(animals.slice(2, -1));
// 输出结果: ["camel", "duck"]

2.2,slice 方法还可以用来将一个类数组(伪数组)对象/集合转换成一个新数组

一个函数中的 arguments 就是一个类数组对象的例子

function list() {return Array.prototype.slice.call(arguments);
}var list1 = list(1, 2, 3); // 打印结果: [1, 2, 3]

3,concat()

concat() 方法用于合并两个或多个数组。此方法不会更改现有数组,而是返回一个新数组。
用法:array.concat(array1,array2,…,arrayN);
当concat()不带任何参数的时候,默认参数为空数组

3.1,基本用法 连接两个数组

const array1 = ['a', 'b', 'c'];
const array2 = ['d', 'e', 'f'];
const array3 = array1.concat(array2);console.log(array3);
// 输出: ["a", "b", "c", "d", "e", "f"]

3.2,使用concat连接三个数组
以下代码将三个数组合并为一个新数组:

const num1 = [1, 2, 3];
const num2 = [4, 5, 6];
const num3 = [7, 8, 9];const numbers = num1.concat(num2, num3);console.log(numbers);
// 输出: [1, 2, 3, 4, 5, 6, 7, 8, 9]

3.3,concat还会 将值连接到数组

以下代码将三个值连接到数组:

const letters = ['a', 'b', 'c'];const alphaNumeric = letters.concat(1, [2, 3]);console.log(alphaNumeric);
// 输出: ['a', 'b', 'c', 1, 2, 3]

3.4,concat还能 合并嵌套数组

以下代码合并数组并保留引用:

const num1 = [[1]];
const num2 = [2, [3]];const numbers = num1.concat(num2);console.log(numbers);
// 输出 [[1], 2, [3]]// 修改 num1 的第一个元素
num1[0].push(4);console.log(numbers);
// 输出 [[1, 4], 2, [3]]

4,扩展运算符(…)

注意:使用展开运算符也只能和上面的方法一样 只能深拷贝一层;

// 对象使用(...)扩展运算符
let obj2 = {a: 1,b: {d: 2},c: [ 3, 4, 5 ]};let obj3 = {...obj2};console.log(obj3);
输出:{ a: 1, b: { d: 2 }, c: [ 3, 4, 5 ] }// 数组使用(...)扩展运算符
let arr1 = [1, { name: 'xinjie' }, [2,3,4]];
let arr2 = [...arr1];
console.log(arr2);
输出:[ 1, { name: 'xinjie' }, [ 2, 3, 4 ] ]

4,深拷贝实现

1,使用JSON对象的parse和stringify

JSON.stringify()是目前前端开发过程中最常用的深拷贝方式,原理是把一个对象序列化成为一个JSON字符串,将对象的内容转换成字符串的形式保存到栈空间,再用JSON.parse()反序列化将JSON字符串变成一个新的对象(新对象是保存在堆空间的)所以可以实现深拷贝,但也有一系列缺点;

JSON对象是ES5中引入的新的类型(支持的浏览器为IE8+)

		let obj5 = {name : 'Eric',age : 18,sex : '男'};先序列化将对象转化为json字符串 这时对象就和下面的没有任何关系了因为字符串是标量类型  所以说只存储在栈空间 和堆空间的对象没有任何关系let json6=JSON.stringify(obj5);// 再将JSON转化会对象let newObj5=JSON.parse(json6);// 进行改变姓名newObj5.name = 'xinjie'console.log("原来的对象",obj5,);console.log("深拷贝过的对象:",newObj5);console.log(Object.is(obj5 ,newObj5)) = false 事实证明两个对象并不相等

通过JSON.stringify实现深拷贝有几点要注意:

  • 拷贝的对象的值中如果有函数,undefined,symbol则经过JSON.stringify()序列化后的JSON字符串中这个键值对会消失
  • 无法拷贝不可枚举的属性,无法拷贝对象的原型链上的属性
  • 拷贝Date引用类型会变成字符串
  • 拷贝RegExp引用类型会变成空对象
  • 对象中含有NaN、Infinity和-Infinity,则序列化的结果会变成null
  • 无法拷贝对象的循环应用(即obj[key] = obj)

2,自定义函数进行深浅拷贝

上面所说的序列化和反序列化虽然比较方便,但由于存在种种问题可用于简单对象的深拷贝;想要实现健壮的深拷贝最好还是我们封装一个可以深拷贝多层的函数,代码如下:


let arr = ['华佗','李时珍','张仲景',['白起','王翦'],'扁鹊','喜来乐'];
// 自定义函数进行深浅拷贝 
function deepCopy(object){let result;if (Object.prototype.toString.call(object) == '[object Object]'){result = {};}else if (Object.prototype.toString.call(object) == '[object Array]'){result = [];}else{return '不符合深拷贝的数据类型';}// 遍历空对象或者是空数组  也就是要拷贝的对象for(let key in object){if (typeof object[key] == 'object'){result[key] = deepCopy(object[key]);}else{result[key] = object[key];}}return result;
}
console.log(deepCopy(arr));  //[object Array]
结果如下:
[ '华佗', '李时珍', '张仲景', [ '白起', '王翦' ], '扁鹊', '喜来乐' ]

End

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

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

相关文章

BAT测开8年工作总结,这些都看懂了,Linux就没问题了

一、文件目录操作 1. ls 命令 ls 命令不仅可以查看 linux 文件夹包含的文件而且可以查看文件权限(包括目录、文件夹、文件权限)查看目录信息等等。 命令格式 ls [选项][目录名] 常用参数 -l :列出长数据串,包含文件的属性与权限数据等-a &#xff…

实战|掌握Linux内存监视:free命令详解与使用技巧

文章目录前言一. free命令介绍二. 语法格式及常用选项三. 参考案例3.1 查看free相关的信息3.2 以MB的形式显示内存的使用情况3.3 以总和的形式显示内存的使用情况3.4 周期性的查询内存的使用情况3.5 以更人性化的形式来查看内存的结果输出四. free在脚本中的应用总结前言 大家…

Dataway 让 Spring Boot 不再需要 Controller、Service、DAO、Mapper 简单接口直接开发。

新的sql语法可以先看一下官网&#xff0c;部署起来之后会用到Dataql&#xff1a; DataQL - 数据查询语言https://www.dataql.net/先看一下效果 接下来来实现一下。 1 创建spring boot项目 导入依赖 <!--begin dataWay--><!--hasor-spring 负责 Spring 和 Hasor 框架之…

Confluence 安装

Confluence 安装 一、购买一台服务器 推荐使用 Ubuntu 版本服务器。 二、安装宝塔面板 官方安装地址 安装地址 Centos 安装脚本 yum install -y wget && wget -O install.sh https://download.bt.cn/install/install_6.0.sh && sh install.sh ed8484bec…

车机系统开发——Android Automotive

Android Automotive介绍 Android Automotive是⼀个基本的Android平台&#xff0c;它运⾏预安装的&#xff08;车载信息娱乐&#xff09;IVI系统&#xff0c;Android应⽤程序以及可选的第⼆⽅和第三⽅Android应⽤程序。 Android Automotive的硬件抽象层(HAL)为Android框架提供…

系统升级丨分享返佣,助力商企实现低成本高转化营销

秉承助力传统经济数字化转型的长远理念 酷雷曼VR再次在VR全景营销中发力 创新研发“分享返佣”功能 进一步拓宽商企VR全景营销渠道 助力商企搭建低成本、高传播、高转化 的VR营销体系 01、什么是“分享返佣”&#xff1f; ●“分享返佣”即“推广”返佣&#xff0c;是酷…

Softing OPC Tunnel——绕过DCOM配置实现OPC Classic广域网通信

一 摘要 Softing OPC Tunnel是dataFEED OPC Suite的一个组件&#xff0c;可避免跨设备OPC Classic通信中出现的DCOM配置问题&#xff0c;同时可保证跨网络数据交换的高性能和可靠性。OPC Tunnel内部集成的存储转发功能&#xff0c;可在连接中断时缓存数据&#xff0c;并在重新…

【数据结构与算法】图 ( 图的存储形式 | 图的基本概念 | 图的表示方式 | 邻接矩阵 | 邻接表 | 图的创建 | 代码示例 )

文章目录一、图的存储形式二、图的基本概念三、图的表示方式1、邻接矩阵2、邻接表四、图的创建 ( 代码示例 )一、图的存储形式 线性表 中的元素 , 有 一个 直接前驱 和 一个 直接后继 ; 树 中的元素 , 有 一个 直接前驱 和 多个 直接后继 ; 图 中的元素 , 有 多个 直接前驱 和…

华为OD机试题,用 Java 解【入栈出栈】问题

最近更新的博客 华为OD机试题,用 Java 解【停车场车辆统计】问题华为OD机试题,用 Java 解【字符串变换最小字符串】问题华为OD机试题,用 Java 解【计算最大乘积】问题华为OD机试题,用 Java 解【DNA 序列】问题华为OD机试 - 组成最大数(Java) | 机试题算法思路 【2023】使…

软件分析笔记02---Intermediate Representation

整体contents compiler &#xff08;source code ——> machine code&#xff09; non-trivial非平凡的 经过 语义分析->语法分析->类型检查等各种trivial的分析&#xff08;前端&#xff09;&#xff0c;生成中间代码IR->进行non-trivial的分析&#xff08;及静…

47个SQL性能优化技巧,看到就是赚到

1、先了解MySQL的执行过程 了解了MySQL的执行过程&#xff0c;我们才知道如何进行sql优化。 &#xff08;1&#xff09;客户端发送一条查询语句到服务器&#xff1b; &#xff08;2&#xff09;服务器先查询缓存&#xff0c;如果命中缓存&#xff0c;则立即返回存储在缓存中的…

Python大数据培训班特色优势及工作方向

Python大数据培训班有多个大数据培训班类型&#xff0c;同时也包括训练营、学徒班、就业班等。 具体班型&#xff1a; 大数据挖掘与人工智能&#xff08;大数据分析&#xff09;学徒班、大数据应用开发学徒班 大数据挖掘与人工智能&#xff08;大数据分析&…

解决MySQL的 Row size too large (> 8126).

&#x1f4e2;欢迎点赞 &#xff1a;&#x1f44d; 收藏 ⭐留言 &#x1f4dd; 如有错误敬请指正&#xff0c;赐人玫瑰&#xff0c;手留余香&#xff01;&#x1f4e2;本文作者&#xff1a;由webmote 原创&#x1f4e2;作者格言&#xff1a;无尽的折腾后&#xff0c;终于又回到…

第14天-ElasticSearch环境配置,构建检索服务及商品上架到ES库

1.ElasticSearch概念 官网介绍&#xff1a;https://www.elastic.co/cn/what-is/elasticsearch/ 官网学习文档&#xff1a;https://www.elastic.co/guide/en/elasticsearch/reference/current/index.html 1.1.ElasticSearch与MySQL的比较 MySQL有事务性,而ElasticSearch没有…

论文笔记:A Time Series is Worth 64 Words: Long-term Forecasting with Transformers

ICLR 2023 比较简单&#xff0c;就不分intro、model这些了 1 核心思想1&#xff1a;patching 给定每个时间段的长度、划分的stride&#xff0c;将时间序列分成若干个时间段 时间段之间可以有重叠&#xff0c;也可以没有每一个时间段视为一个token 1.1 使用patching的好处 降…

糖化学试剂55520-67-7,5-vinyl-2-deoxyuridine,5-乙烯基-2-脱氧尿苷特点分析说明

5-vinyl-2-deoxyuridine(5-VdU)&#xff0c;5-vinyl-2-deoxyuridine&#xff0c;5-Vinyldeoxyuridine5-乙烯基-2-脱氧尿苷 | CAS&#xff1a;55520-67-7 | 纯度&#xff1a;95%试剂信息&#xff1a;CAS&#xff1a;55520-67-7所属类别&#xff1a;糖化学分子量&#xff1a;C11H…

MySQL索引类型(type)分析

type索引类型 system > const > eq_ref > ref > range > index > all 优化级别从左往右递减&#xff0c;没有索引的⼀般为’all’。推荐优化目标&#xff1a;至少要达到 range 级别&#xff0c; 要求是 ref 级别&#xff0c; 如果可以是 const 最好&#xff…

单通道说话人语音分离——DPRNN(Dual-Path Recurrent Neural Network)

参考文献&#xff1a;《DUAL-PATH RNN: EFFICIENT LONG SEQUENCE MODELING FOR TIME-DOMAIN SINGLE-CHANNEL SPEECH SEPARATION》 DPRNN网络是Con-Tasnet的改进网络 Con-Tasnet介绍详情请看上一篇文章 单通道说话人语音分离——Conv-TasNet(Convolutional Time-domain audio…

UWB到底是什么技术?

什么是空间感知能力 所谓的空间感知能力&#xff0c;就是感知方位的能力。更直接一点&#xff0c;就是定位能力。说白了&#xff0c;利用UWB技术&#xff0c;手机和智能设备可以更精准地实现室内定位&#xff0c;不仅可以感知自己的位置&#xff0c;还可以感知周边其它手机或设…

多任务学习概述

文章目录前言1 文章信息2 背景、目的、结论2.1 背景2.1.1 多任务的类型分类2.1.1.1 相关任务的分类2.1.1.2 将输入变输出的逆多任务学习2.1.1.3 对抗性多任务学习2.1.1.4 辅助任务提供注意力特征的多任务学习2.1.1.5 附加预测性辅助任务的多任务学习3 内容与讨论3.1 多任务学习…