对浅拷贝的理解

news/2024/10/22 16:41:19/

问题背景

我之前一直以为浅拷贝出来的新对象和旧对象的引用地址是相同的,但是通过Object和===发现浅拷贝的新对象和旧对象的引用地址不同!!

   const obj1 = { name: "Alice", test: { age: 12 } };const obj4 = Object.assign({}, obj1); // 浅拷贝obj4.name = "hhh";obj4.test.age = 99;console.log("obj1", obj1);console.log("obj4", obj4);const obj2 = { name: "Alice" };const obj3 = obj1;console.log(Object.is(obj1, obj2)); // false,因为它们的引用地址不同console.log(Object.is(obj1, obj3)); // true,因为它们指向同一个对象console.log(Object.is(obj1, obj4)); // false!!!console.log(obj1 === obj2); // falseconsole.log(obj1 === obj3); // trueconsole.log(obj1 === obj4); // false!!!

甚至当对象不止一层的时候,也是引用对象不同
因为我一直以为不止一层,那么浅拷贝就直接拷贝地址,那么引用地址总应该相同了吧,唉

   const obj5 = {test: { age: 12 } };const obj6 = Object.assign({}, obj5); // 浅拷贝console.log(Object.is(obj5, obj6)); // false!!!console.log(obj5 === obj6); // false!!!

还是有疑问

既然浅拷贝出来的对象引用地址不同,为什么obj1.test.age也修改了

const obj1 = { name: "Alice", test: { age: 12 } };const obj4 = Object.assign({}, obj1);obj4.name = "hhh";obj4.test.age = 99;console.log("obj1", obj1);console.log("obj4", obj4);

这是因为浅拷贝只会复制对象的第一层属性,而不会递归复制对象中嵌套的对象。所以虽然 obj1 和 obj4 是两个不同的对象,但它们的 test 属性引用的是同一个对象

   console.log(Object.is(obj1.test, obj4.test)); // true!!!console.log(obj1.test === obj4.test); // true!!!

修改 obj4.test.age 实际上修改了 test 属性指向的对象,因此 obj1 中的 test 属性也会受到影响。

要解决这个问题,你需要使用深拷贝而不是浅拷贝。深拷贝会递归地复制对象及其所有嵌套的对象,确保所有对象都是独立的,没有共享引用。

在插一句

    const obj7 = { name: "Alice" };const obj8 = Object.assign({}, obj7); // 浅拷贝console.log(Object.is(obj7.name, obj8.name)); // trueconsole.log(obj7.name === obj8.name); // true

在这段代码中,obj7 和 obj8 中的 name 属性都是字符串,它们的值是相同的,因此 Object.is(obj7.name, obj8.name) 和 obj7.name === obj8.name 都会返回 true。

需要注意的是,这里的比较并不是比较两个对象的引用地址,而是比较它们的值。在 JavaScript 中,字符串是基本数据类型,比较时会直接比较它们的值。
要判断两个字符串的引用是否相同,可以使用严格相等运算符(===)或 Object.is() 方法进行比较。这会比较字符串的引用地址是否完全相同。

javascript">const str1 = "hello";
const str2 = "hello";
const str3 = new String("hello");console.log(str1 === str2); // true,直接量相同
console.log(str1 === str3); // false,str3 是一个对象,与 str1 的引用不同
console.log(Object.is(str1, str2)); // true
console.log(Object.is(str1, str3)); // false

在这个例子中,str1str2 是直接量,它们的引用地址相同,因此严格相等运算符和 Object.is() 方法都会返回 true。而 str3 是通过构造函数 String 创建的字符串对象,与直接量的引用地址不同,因此比较结果为 false

总结

浅拷贝出来的对象和旧对象的引用地址是不同的。在浅拷贝过程中,会创建一个新的对象,该对象包含了源对象的所有可枚举属性的副本。因此,尽管浅拷贝后的对象可能与源对象具有相同的属性值,但它们是两个不同的对象,存储在内存中的不同位置,拥有不同的引用地址。

在这里插入图片描述

引用别人的文章:

http://t.csdnimg.cn/zSoTn


let arrayA = [1, '这是一个字符串', undefined, null, { obj: '这是一个obj' }];
console.log('原始的arrayA', arrayA)//原始的arrayA [1, 2, 3, 4, 5, 6, 7]
let arrayB = Array.from(arrayA)//浅拷贝(注意,浅拷贝只会拷贝一层)
let arrayC = arrayA//应用arrayA的堆地址arrayA[0] = 99
arrayA[1] = "修改一下这个字符串"
arrayA[2] = "修改一下这个undefind"
arrayA[3] = "修改一下这个null"
arrayA[4].obj = "修改一下这个obj"console.log('arrayA', arrayA)//[99, '修改一下这个字符串', 修改一下这个undefind, 修改一下这个null, { obj: '修改一下这个obj' }];
//arrayB是由Array.form浅拷贝来的,
console.log('arrayB', arrayB)//[1, '这是一个字符串', undefined, null, { obj: '修改一下这个obj' }]
//arrayC地址应用(arrayC是指向arrayA这个数组对象的堆内存的内存地址),所以arrayA改变后arrayC也会改变,因为它两指向的是同一个内存地址;
console.log('arrayC', arrayC)//[99, '修改一下这个字符串', 修改一下这个undefind, 修改一下这个null, { obj: '修改一下这个obj' }];

在这里插入图片描述


http://www.ppmy.cn/news/1442444.html

相关文章

时间序列生成数据,TransformerGAN

简介:这个代码可以用于时间序列修复和生成。使用transformer提取单变量或者多变时间窗口的趋势分布情况。然后使用GAN生成分布类似的时间序列。 此外,还实现了基于prompt的数据生成,比如指定生成某个月份的数据、某半个月的数据、某一个星期的…

【GitHub】主页简历优化

【github主页】优化简历 写在最前面一、新建秘密仓库二、插件卡片配置1、仓库状态统计2、Most used languages(GitHub 常用语言统计)使用细则 3、Visitor Badge(GitHub 访客徽章)4、社交统计5、打字特效6、省略展示小猫 &#x1f…

HTTP如何自动跳转到HTTPS,免费SSL证书如何获取

如今HTTPS已经成为了网站标配,然而,对于一些刚刚起步的网站或是个人博客而言,如何自动跳转到HTTPS,以及免费SSL证书的获取,可能还是一个需要解决的问题。下面就来详细解答这两个问题。 我们需要先了解HTTP与HTTPS的区…

FreeBSD系统安装Tlsla P4专业AI计算卡(待续)

首先打开FreeBSD下的linux兼容服务 sysrc linux_enable"YES" service linux start 安装nvidia英伟达驱动 # 由shkhln提供,官网:https://github.com/shkhln/libc6-shim pkg install libc6-shim# nvidia驱动占用空间较大,需要2G空…

Win linux 下配置adb fastboot

一、Win配置adb & fastboot 环境变量 主机:Win10,除了adb fastboot需要设置变量之外,驱动直接安装即可 win下adb fastboot 下载地址:https://download.csdn.net/download/u012627628/89215420 win下qcom设备驱动下载地址&a…

最大连续1的个数 ||| ---- 滑动窗口

题目链接 题目: 分析: 题目中说可以将最多k个0翻转成1, 如果我们真的这样算就会十分麻烦, 所以我们可以换一种思路: 找到一个最长的子数组, 最多有k个0解法一: 暴力解法: 找到所有的最多有k个0的子字符串, 返回最长的解法二: 找到最长的子数组, 我们可以想到"滑动窗口算…

模拟LinkedList实现的双向循环链表

1. 前言 前文我们分别实现了不带哨兵的单链表,带哨兵节点的双向链表,接着我们实现带哨兵节点的双向循环链表.双向循环链表只需一个哨兵节点,该节点的prev指针和next指针都指向了自身哨兵节点. 2. 实现双向循环链表的代码 例 : //模拟双向…

三个目前主流的计算机视觉软件

计算机视觉是人工智能的一个重要分支,它涉及到使计算机能够理解和解释图像和视频数据。近年来,计算机视觉领域取得了显著的进展,尤其是在深度学习的帮助下。尽管如此,将计算机视觉的能力直接与人类的视觉能力进行比较并不完全准确…