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

前端深拷贝与浅拷贝的实现

1、浅拷贝和深拷贝的定义
1.1、浅拷贝

有两种方式,一种是把一个对象里面的所有的属性值和方法都复制给另一个对象,另一种是直接把一个对象赋给另一个对象,使得两个都指向同一个对象。浅拷贝对内存地址的复制,让目标对象指针和源对象指向同一片内存空间。

1.2、深拷贝

深拷贝是指拷贝对象的具体内容,其内存地址是自主分配的,拷贝结束之后俩个对象虽然存的值是一样的,但是内存地址不一样,俩个对象互相不影响,互不干涉。

数据类型的值传递和地址传递

JavaScript的数据类型可以分为基本数据类型和引用数据类型

基本数据类型有:Number、String、Boolean、Null、Undefined、Symbol
引用数据类型有:Object、Function、Array、Regexp、Date

普通数据类型和对象的存储方式:
   普通数据类型一般是存储在栈中的,而对象一般是存储在堆中的,同时在栈中存放了一个地址数据指向堆中的数据。当调用对象时,首先会获取栈中的地址,根据该地址去堆中找到该对象数据。

针对普通类型,在赋值过程中一般是值传递

//Number
var num1=12;
var num2=num1;
num2=34;
console.log(num1,num2);//12,34
//String
var str1="abc";
var str2=str1;
str2="def";
console.log(str1,str2);//abc,def


针对引用类型中的对象和数组,在赋值过程中一般是地址传递

//对象
var obj1 = { name: 'jack' }; 
var obj2 = obj1; //复制obj1的引用
obj2.name = 'mary';
//此时obj1和obj2全都指向一个地址,修改地址值,obj1和obj2的值都会改变
console.log(obj1.name, obj2.name);//mary,mary
// []
a = ['a', 'b', 'c']; b = a; b[1] = 'd';
console.log(a, b)


2、浅拷贝实现的具体方式
2.1、数字方法slice()


var arr1 = [
        { number: 1 },
        { number: 2 },
        { number: 3 }
];
var arr2 = arr1.slice();//复制arr1在栈中的引用地址
arr2[0].number = 9//将复制过来的引用地址的指向修改为9,所以arr和arr2都会改变
console.log(arr1[0].number, arr2[0].number);//9,9

原因:

arr2拷贝了arr1在栈内存中的地址,也就是arr2和arr1共用存储在堆内存的数据;同理得,当arr2发生改变的时候,arr1也会随之改变。



2.2、Object.assign

Object.assign() 方法用于将所有可枚举属性的值从一个或多个源对象分配到目标对象。它将返回目标对象。

var arr1 = [//两层数据
        { number: 1 },
        { number: 2 },
        { number: 3 }
];
var obj1 = { name: 'jack' }//一层数据
var obj2 = Object.assign({}, obj1);//此时obj1为一层数据,复制的是对象中的属性值
obj2.name = 'mary'
var arr2= Object.assign({}, arr1)//复制的是数组中的对象在栈中的的引用地址
arr2[0].number = 99
console.log(obj1.name, obj2.name, arr1[0].number, arr2[0].number);//jack mary 99 99


2.3、for…in…

通过for…in…遍历对象将源对象的值拷贝到另一个对象上,并返回另一个对象。浅拷贝只能遍历一层对象,当数据是嵌套对象则需要深拷贝。

var qianCopy = function (obj) {
            var result= obj.constructor();//声明参数的一个空构造函数
            // 遍历对象中的属性及方法
            for (var key in obj) {
                // 判断对象有没有相应的key
                if (obj.hasOwnProperty(key)) {
                    // 把对象相应key对象的值赋值给另外一个对象相应的key对应的值
                    result[key] = obj[key];
                }
            }
            return result
}


var obj1 = { name: 'jack' }; 
var obj2 = qianCopy(obj1); //复制obj1的引用
obj2.name = 'mary';
//此时obj1和obj2全都指向一个地址,修改地址值,obj1和obj2的值都会改变
console.log(obj1.name, obj2.name);//jack,mary


3、深拷贝的具体实现
3.1、JSON.parse(JSON.stringify())

JSON.parse(JSON.stringify())一般用于深拷贝:JSON.stringify()将JS对象序列化转化为JSON字符串,再利用JSON.parse()反序列化,将JSON字符串还原成对象。该方法只能用于可枚举属性。

var arr1 = [
      { number: 1 },
      { number: 2 },
      { number: 3 }
];
var arr2 = JSON.parse(JSON.stringfy(arr1))//此时是将arr1中所有属性的值复制给arr2,两者相互独立
arr2[0].number = 199
console.log(arr1[0].number, arr2[0].number);//1,199   


当然JSON.parse(JSON.stringify())并不是一种完美实现深拷贝的方法,存在以下缺陷:

1.当深拷贝对象为函数、Undefined时,会把函数、Undefined丢失,无法拷贝。
2.当深拷贝对象为Regexp、Error对象,序列化结果为空对象
3.当深拷贝对象中存在NaN、infinity、-infinity时,序列化会变成Null


3.2、递归

面试题:使用递归完成深拷贝对象

function shenCopy(obj){
    //创建参数的构造函数对象
    var result=obj.constructor();
    if(typeof obj!==Object){//当传入参数不为Object类型时,直接返回该参数
        return obj;
    }else{
        for(let key in obj){
            //递归核心:将嵌套对象递归得到的返回值赋予新建的构造对象
            result[key]=shenCopy(obj[key]);
        }
    }
    return result;
}

相关文章:

前端深拷贝与浅拷贝的实现

1、浅拷贝和深拷贝的定义 1.1、浅拷贝 有两种方式,一种是把一个对象里面的所有的属性值和方法都复制给另一个对象,另一种是直接把一个对象赋给另一个对象,使得两个都指向同一个对象。浅拷贝对内存地址的复制,让目标对象指针和源…...

哆啦百宝箱APP

专门为年轻人设计的APP,主打的免费、无恶心广告、不获取任何个人信息。 哆啦百宝箱 ● 永久免费 ● 无恶心广告 ● 种类巨多 ● 全民参与 ● 爆款功能 ● 用心创造 哆啦百宝箱 提供了从日常、图片、查询、设备、趣味、娱乐等多方面的功能, 操作简单&a…...

lv9 嵌入式开发 数据库sqlite

1 数据库基本概念 数据(Data) 能够输入计算机并能被计算机程序识别和处理的信息集合 数据库 (Database) 数据库是在数据库管理系统管理和控制之下,存放在存储介质上的数据集合 2 常用的数据库 大型数据库…...

「Verilog学习笔记」异步复位的串联T触发器

专栏前言 本专栏的内容主要是记录本人学习Verilog过程中的一些知识点,刷题网站用的是牛客网 分析 这道题目里我们有两个需要明确的点: 1. 什么是异步复位 2. 什么是串联的T触发器 关于第一个点,可以看我的这篇文章,已经整理好了&a…...

什么是51单片机,,如何写代码,并且烧录?

文章目录 1.单片机介绍2.Keil 5操作1.打开Keil 5 3 新建工程3.添加文件并写代码4.添加到group5,设置6.check7.编译8.打开头文件9 调整编辑器 4.烧录1.烧录程序2.串口查询 5.Debug1.首先编译2.调试3.查询 6 51单片机汇编指令1.格式2.符号3.寻址4.数据传送与交换指令5.交换指令6 …...

Multer 实现文件上传功能

Multer 实现文件上传功能 前言:Multer 安装和使用1、安装2、使用2-1 前端代码2-2 后端代码3、实现效果前言: post请求一般有4种数据类型: application/x-www-form-urlencodedmultipart/form-dataapplication/jsontext/xml相应后端Express会使用不同的中间件来解析不同类型的…...

Excel·VBA工作表导出为图片

《Excel转图片别再截图啦!用这4个方法,高清且无损!》,excel转为图片一般方法较为简单,那么能否使用vba将excel转为图片 选中区域导出为图片 zoom设置为2,导出图片较为清晰 Sub 选中区域导出为图片()Dim …...

【零基础抓包】Fiddler超详细教学(一)

​Fiddler 1、什么是 Fiddler? Fiddler 是一个 HTTP 协议调试代理工具,它能够记录并检查所有你的电脑和互联网之间的 HTTP 通讯。Fiddler 提供了电脑端、移动端的抓包、包括 http 协议和 https 协议都可以捕获到报文并进行分析;可以设置断点调试、截取…...

快速入手maven

文章目录 Maven介绍Maven安装和配置基于IDEA的Maven工程创建梳理Maven工程GAVP属性Idea构建Maven JavaSE工程Idea构建Maven JavaEE工程1. 手动创建2. 插件方式创建 Maven工程项目结构说明Maven核心功能依赖和构建管理依赖传递和冲突依赖导入失败场景和解决方案扩展构建管理和插…...

Mysql Binlog日志

Mysql Binlog是二进制格式的日志文件,但是不能把binlog文件等同于OS系统某目录下的具体文件,这是狭隘的。Binlog是用来记录Mysql内部对数据库的改动(只记录对数据的修改操作),主要用于数据库的主从复制、数据同步以及增…...

高级深入--day45

官方站点:GitHub - rmax/scrapy-redis: Redis-based components for Scrapy. scrapy-redis的官方文档写的比较简洁,没有提及其运行原理,所以如果想全面的理解分布式爬虫的运行原理,还是得看scrapy-redis的源代码才行。 scrapy-r…...

shell_66.Linux修改或移除信号捕获

修改或移除信号捕获 要想在脚本中的不同位置进行不同的信号捕获处理,只需重新使用带有新选项的 trap 命令即可: $ cat trapmod.sh #!/bin/bash #Modifying a set trap # trap "echo Sorry...Ctrl-C is trapped." SIGINT # count1 whi…...

5 ip的分配

如上一节所述,需要和其他设备通信,那么需要先配置ip. 1、如何配置ip 1.可以使用 ifconfig,也可以使用 ip addr 2.设置好了以后,用这两个命令,将网卡 up 一下,就可以了 //---------------------------- 使…...

【Python机器学习】零基础掌握StackingClassifier集成学习

如何精确地预测花的种类?一个简单但强大的方法引入了! 在现实生活中,生物学家和园艺爱好者经常面临一个问题:如何准确地识别和分类不同种类的花?这不仅仅是一个纯粹的学术问题,也有实际应用,比如在植物育种、生态研究等方面。为 了解决这个问题,一种叫做堆叠分类(St…...

Spring Boot 常见面试题

目录 1.Spring Boot 快速入门什么是 Spring Boot?有什么优点?Spring Boot 与 Spring MVC 有什么区别?Spring 与 Spring Boot 有什么关系?✨什么是 Spring Boot Starters?Spring Boot 支持哪些内嵌 Servlet 容器?如何设…...

利用大语言模型(LLM )提高工作效率

日常工作就是面向 google/ 百度编程,除了给变量命名是手动输入,大多时候就是通过搜索引擎拷贝别人的代码,或者找到旧项目一段代码拷贝过来使用。这无疑是开发人员的真实写照;然而,通过搜索引擎搜索答案,无疑…...

[Linux打怪升级之路]-信号的产生

前言 作者:小蜗牛向前冲 名言:我可以接受失败,但我不能接受放弃 如果觉的博主的文章还不错的话,还请点赞,收藏,关注👀支持博主。如果发现有问题的地方欢迎❀大家在评论区指正 目录 一、信号基础…...

Python教程---Python基础语法

1.程序中的几个基本概念 (1).表达式 表达式就是一个类似于数学公式的东西 比如:10 + 5 8 - 4 表达式一般仅仅用了计算一些结果,不会对程序产生实质性的影响 如果在交互模式中输入一个表达式,解释器会自动将表达式的结果输出 (2).语句 在程序中语句一般需要完成某种功能,…...

echarts 画散点图, x周,y周在指定位置标志一下

文章目录 echarts 画散点图, x周,y周在指定位置标志一下示例一例子二示例三 echarts 画散点图, x周,y周在指定位置标志一下 示例一 let scatterData {data: [[[-0.2, -0.6],[0.4, 0.3],[0.1, 0.4],[0.3, 0.5],[0.09, 0.1],[0.7,…...

Unity地面交互效果——3、曲面细分基础知识

大家好,我是阿赵。   之前介绍了使用动态法线贴图混合的方式模拟轨迹的凹凸感,这次来讲一下更真实的凹凸感制作。不过在说这个内容之前,这一篇先要介绍一下曲面细分着色器(Tessellation Shader)的用法。 一、为什么要做曲面细分 之前通过法…...

linux之kylin系统nginx的安装

一、nginx的作用 1.可做高性能的web服务器 直接处理静态资源(HTML/CSS/图片等),响应速度远超传统服务器类似apache支持高并发连接 2.反向代理服务器 隐藏后端服务器IP地址,提高安全性 3.负载均衡服务器 支持多种策略分发流量…...

RocketMQ延迟消息机制

两种延迟消息 RocketMQ中提供了两种延迟消息机制 指定固定的延迟级别 通过在Message中设定一个MessageDelayLevel参数,对应18个预设的延迟级别指定时间点的延迟级别 通过在Message中设定一个DeliverTimeMS指定一个Long类型表示的具体时间点。到了时间点后&#xf…...

【OSG学习笔记】Day 18: 碰撞检测与物理交互

物理引擎(Physics Engine) 物理引擎 是一种通过计算机模拟物理规律(如力学、碰撞、重力、流体动力学等)的软件工具或库。 它的核心目标是在虚拟环境中逼真地模拟物体的运动和交互,广泛应用于 游戏开发、动画制作、虚…...

C++:std::is_convertible

C++标志库中提供is_convertible,可以测试一种类型是否可以转换为另一只类型: template <class From, class To> struct is_convertible; 使用举例: #include <iostream> #include <string>using namespace std;struct A { }; struct B : A { };int main…...

React第五十七节 Router中RouterProvider使用详解及注意事项

前言 在 React Router v6.4 中&#xff0c;RouterProvider 是一个核心组件&#xff0c;用于提供基于数据路由&#xff08;data routers&#xff09;的新型路由方案。 它替代了传统的 <BrowserRouter>&#xff0c;支持更强大的数据加载和操作功能&#xff08;如 loader 和…...

Java如何权衡是使用无序的数组还是有序的数组

在 Java 中,选择有序数组还是无序数组取决于具体场景的性能需求与操作特点。以下是关键权衡因素及决策指南: ⚖️ 核心权衡维度 维度有序数组无序数组查询性能二分查找 O(log n) ✅线性扫描 O(n) ❌插入/删除需移位维护顺序 O(n) ❌直接操作尾部 O(1) ✅内存开销与无序数组相…...

【Redis技术进阶之路】「原理分析系列开篇」分析客户端和服务端网络诵信交互实现(服务端执行命令请求的过程 - 初始化服务器)

服务端执行命令请求的过程 【专栏简介】【技术大纲】【专栏目标】【目标人群】1. Redis爱好者与社区成员2. 后端开发和系统架构师3. 计算机专业的本科生及研究生 初始化服务器1. 初始化服务器状态结构初始化RedisServer变量 2. 加载相关系统配置和用户配置参数定制化配置参数案…...

UR 协作机器人「三剑客」:精密轻量担当(UR7e)、全能协作主力(UR12e)、重型任务专家(UR15)

UR协作机器人正以其卓越性能在现代制造业自动化中扮演重要角色。UR7e、UR12e和UR15通过创新技术和精准设计满足了不同行业的多样化需求。其中&#xff0c;UR15以其速度、精度及人工智能准备能力成为自动化领域的重要突破。UR7e和UR12e则在负载规格和市场定位上不断优化&#xf…...

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…...

基于Java Swing的电子通讯录设计与实现:附系统托盘功能代码详解

JAVASQL电子通讯录带系统托盘 一、系统概述 本电子通讯录系统采用Java Swing开发桌面应用&#xff0c;结合SQLite数据库实现联系人管理功能&#xff0c;并集成系统托盘功能提升用户体验。系统支持联系人的增删改查、分组管理、搜索过滤等功能&#xff0c;同时可以最小化到系统…...