【JS】浅谈浅拷贝与深拷贝

浅拷贝与深拷贝

  • 前言
  • 一、浅拷贝?
    • 1.1是什么?
    • 1.2做什么?
    • 1.3为什么使用?
    • 1.4实现方式?
    • 1.5 应用场景?
  • 二、深拷贝?
    • 2.1是什么?
    • 2.2做什么?
    • 2.3为什么使用?
    • 2.4实现方式?
    • 2.5应用场景?
  • 三、区别
  • 总结


前言

我们对数组或者对象进行操作的时候,有时并不想操作原始对象,就会将对象或数组复制出新一份,在新的一份中进行操作。

深拷贝与浅拷贝是常用于对象或数组进行复制。
在这里插入图片描述


一、浅拷贝?

1.1是什么?

浅拷贝是指复制对象时,只复制对象的引用,而不复制引用指向的对象本身。如果属性是基本类型,拷贝的就是基本类型的值;如果属性是引用类型,拷贝的就是内存中的地址。

先用一张图理解这句话
在这里插入图片描述
当B从A中复制一份时,他们在内存地址中指向仍旧是同一个,如果此时A改变了某些值,因为B和A指向是相同的,B此时也会跟着改变。也就是说B只是复制A在内存地址的引用,并没复制A的本身。

1.2做什么?

浅拷贝它复制了原始对象中的所有字段到新的对象中,对于值类型,复制操作不会对原对象的字段值有任何影响;

对于引用类型,新的对象对引用类型中的字段赋值等操作,会对原引用类型对象中的字段进行更改。

浅拷贝经常用于在不需要深度复制对象的情况下快速复制对象。

1.3为什么使用?

  • 内存使用优化:浅拷贝允许多个对象共享相同的数据区,这样可以显著减少内存的消耗。特别是当处理大型数据结构。
  • 性能提升:减少拷贝的次数,从而提升程序的运行效率。
  • 特定需求:只要复制对象的顶层数据,而不是对象的所有层次。

1.4实现方式?

  • 扩展运算符(…)
const originalArray = [1, 2, [3, 4]];  
const shallowCopyArray = [...originalArray]; 
  • Object.assign()
const originalArray = { a: 1, b: { c: 2 } };  
const shallowCopyArray = Object.assign({},originalArray); 
  • Array.prototype.slice(), Array.prototype.concat()
const originalArray = [1, 2, [3, 4]];  
const shallowCopyArray = originalArray.slice(); const shallowCopyArray = originalArray.concat(); 

1.5 应用场景?

  • 组件间传值:子组件只是读取这些数据而不进行修改
  • 计算属性或方法中的临时变量:基于当前组件的状态或传入的参数创建一些临时变量。如果这些临时变量只是简单地读取状态或参数的值,而不进行修改

二、深拷贝?

2.1是什么?

深拷贝是指复制对象时,不仅复制对象本身,还复制对象所引用的所有对象,直到所有引用的对象都被完全复制。

先用一张图理解这句话
在这里插入图片描述
当B从A中复制一份时,不仅新创建了B对象,还创造一块新的内存,此时B和A在内存中的指向不再是同一块。如果A改变了,B不会受影响。

2.2做什么?

深拷贝独立创建新的对象和开辟一块新的内存,对于值和引用类型,复制操作不会对原对象的字段值有任何影响;

深拷贝经常用于不影响原对象情况下复制新对象。深拷贝相对于浅拷贝来说,更加复杂耗时,但可以确保数据的安全性。

2.3为什么使用?

  • 避免数据冲突:使用深拷贝可以确保新对象与原始对象完全独立,对其中一个对象的修改不会影响另一个。
  • 确保数据完整:深拷贝可以复制对象的所有层级,从而确保整个对象的完整性。
  • 特定需求:不影响原始数据操作。

2.4实现方式?

  • JSON.stringify()
const obj2=JSON.parse(JSON.stringify(obj1));

但是这种方式存在弊端,会忽略undefined、symbol和函数

const obj = {name: 'A',name1: undefined,name3: function() {},name4:  Symbol('A')
}
const obj2 = JSON.parse(JSON.stringify(obj));
console.log(obj2); // {name: "A"}
  • 循环递归
function deepClone(obj, hash = new WeakMap()) {if (obj === null) return obj; // 如果是null或者undefined我就不进行拷贝操作if (obj instanceof Date) return new Date(obj);if (obj instanceof RegExp) return new RegExp(obj);// 可能是对象或者普通的值  如果是函数的话是不需要深拷贝if (typeof obj !== "object") return obj;// 是对象的话就要进行深拷贝if (hash.get(obj)) return hash.get(obj);let cloneObj = new obj.constructor();// 找到的是所属类原型上的constructor,而原型上的 constructor指向的是当前类本身hash.set(obj, cloneObj);for (let key in obj) {if (obj.hasOwnProperty(key)) {// 实现一个递归拷贝cloneObj[key] = deepClone(obj[key], hash);}}return cloneObj;
}
  • _.cloneDeep()
const _ = require('lodash');
const obj = {a: 1,
};
const obj1 = _.cloneDeep(obj);

2.5应用场景?

  • 组件间数据传递:子组件对数据的修改不会影响到父组件或其他兄弟组件。

  • Vuex状态管理:在Vuex中,状态是响应式的,当状态改变时,视图也会自动更新。通过深拷贝,我们可以创建一个状态的独立副本,在组件内部进行修改,而不会触发全局状态的更新。

  • 避免直接修改props:需要基于props的数据进行修改,可以先使用深拷贝创建一个副本,然后在副本上进行修改。

三、区别

  • 共同点:
    • 都是复制数据
  • 不同点:
    • 浅拷贝是复制内存中的地址,拷贝前后的对象,因为引用类型共享了同一块内存,修改会相互影响。基本类型值不变,引用类型会改变
    • 深拷贝是递归拷贝深层次,属性为对象时,深拷贝是新开栈,两个对象指向不同的地址。基本类型和引用类型不改变

总结

  • 浅拷贝
    • 引用同一块内存,会影响原数据
    • 基本类型值不变,引用类型会改变
    • 实现方式:… , Object.assign() , slice(),concat()
  • 深拷贝
    • 新开辟内存,不影响原数据
    • 基本类型和引用类型不改变
    • 实现方式:循环递归 , JSON.stringify() , loadsh库中_.cloneDeep()
      在这里插入图片描述

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

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

相关文章

闪回技术

目录 闪回技术 恢复mybonus表 彻底删除mybonus表 清空回收站 Oracle从入门到总裁:​​​​​​https://blog.csdn.net/weixin_67859959/article/details/135209645 闪回技术 Flash Back 给予用户最为直接的支持之一就是给了用户后悔的机会 但是现在如果用户想去操作这个…

基于Java+SpringBoot+vue+element实现物流管理系统

基于JavaSpringBootvueelement实现物流管理系统 博主介绍:多年java开发经验,专注Java开发、定制、远程、文档编写指导等,csdn特邀作者、专注于Java技术领域 ** 作者主页 央顺技术团队** 欢迎点赞 收藏 ⭐留言 文末获取源码联系方式 文章目录 基于JavaSpr…

Git 遇到合并冲突如何解决

Git 遇到合并冲突解决方法 前言一、解决冲突 回滚二、将解冲突后的文件 提交到暂存区三、git commit 提交代码到本地Git仓库四、git push 提交五、注意 ​ 2024/3/13 前言 Git突然无法拉取下来,显示有合并冲突: 步骤:解决回滚解决冲突后、添…

Android 异常重启--踩坑归来--干货篇

如果你未对自己的app进行过处理,那么线上各种偶发莫名其妙的闪退、白屏、数据丢失,请检查一下是否因此而引发的。 起因 异常重建指的是非配置变更情况下导致的 Activity 重新创建。 常见场景大多是因为内存等资源不足,从而导致后台应用被系…

ClinicalMamba:长距离不垮,超模也望尘莫及;定制化信息提取,个性化精确到点

ClinicalMamba:长距离不垮,超模也望尘莫及;定制化信息提取,个性化精确到点 1. 引言2. 相关工作早期临床语言模型的局限性Clinical BERT和ClinicalBERT等模型的进步GatorTron和NYUTron等大模型的贡献提出长文本处理的需求和之前方法…

C++第四弹---类与对象(一)

✨个人主页: 熬夜学编程的小林 💗系列专栏: 【C语言详解】 【数据结构详解】【C详解】 类与对象 1、面向过程和面向对象初步认识 2、类的引入 3、类的定义 4、类的访问限定符及封装 4.1、访问限定符 4.2、封装 5、类的作用域 6、类的…

ElasticSearch之Nested对象

写在前面 本文看下es的nested嵌套对象相关内容。 1:es用了啥范式? 在关系型数据库中定义了6大数据库范式,即1,2,3,BC,4,5的NF(normal form),分别如下: 1N…

Apache Paimon 的 CDC Ingestion 概述

CDC Ingestion 1)概述 Paimon支持schema evolution将数据插入到Paimon表中,添加的列将实时同步到Paimon表,并且无需重启同步作业。 目前支持的同步方式如下: MySQL Synchronizing Table: 将MySQL中的一个或多个表同步到一个Pa…

Day15 面向对象进阶——接Day14

Day15 面向对象进阶——接Day14 文章目录 Day15 面向对象进阶——接Day14一、访问修饰符二、Object三、深入String的equals()方法四、final 一、访问修饰符 1、含义:修饰类、方法、属性,定义使用的范围 2、经验: 2.1.属性一般使用private修…

Linux第77步_处理Linux并发的相关函数

了解linux中的“原子整形数据”操作、“原子位数据”操作、自旋锁、读写锁、顺序锁、信号量和互斥体,以及相关函数。 并发就是多个“用户”同时访问同一个共享资源。如:多个线程同时要求读写同一个EEPROM芯片,这个EEPROM就是共享资源&#x…

面试六--TCP粘包问题

1.流式传输协议 流式传输协议(Streaming Protocol)是一种用于在网络上传输数据的通信协议,它允许数据以连续的流的形式进行传输,而不是一次性发送完整的数据包。流式传输协议即协议的内容是像流水一样的字节流,内容与内…

【Flutter】报错Target of URI doesn‘t exist ‘package:flutter/material.dart‘

运行别人项目 包无法导入报错:Target of URI doesn’t exist ‘package:flutter/material.dart’ 解决方法 flutter packages get成功 不会报错