javascript中的浅拷贝深拷贝是什么?一文带你搞懂,不再犯错(代码片段)

前端修罗场 前端修罗场     2022-11-28     499

关键词:

⭐️ 本文首发自 前端修罗场,是一个由 资深开发者 独立运行 的专业技术社区,我专注 Web 技术、模拟面试、简历修改、Web3、区块链以及职业发展。创作的 《前端面试复习笔记》(点击阅读原文订阅),广受好评,已帮助多位同学提升实力、拿到 offer。现在订阅,私聊博主即可获取一次 免费的模拟面试/简历指导服务,帮你评估知识点的掌握程度,获得更全面的学习指导意见!

浅拷贝和深拷贝是Javascript中抛出的术语,如果你以前没有听说过,可能会感到困惑。我们经常听说,像 slicefilter 这样的数组方法会对原始数组进行浅层复制

一个数组或对象的浅层拷贝是指它们在内存中都有相同的引用。这意味着,如果你 改变了浅层拷贝,它也可能改变原始拷贝。我说可能,因为情况并不总是这样的。

让我们看一个使用 slice的例子。

let arrayOne = [ '⚡️', '🔎', '🔑', '🔩' ];
let arrayOneSlice = arrayOne.slice(2, 3);  

console.log(arrayOne); // [ '⚡️', '🔎', '🔑', '🔩' ]
console.log(arrayOneSlice); // [ '🔑' ]

这里我们有一个数组,然后我们在变量 arrayOneSlice 中进行 slice 操作。这两个数组在内存中都有相同的引用,因为 slice 对它们做了一个浅层拷贝。所以如果我们试图更新 arrayOneSlice ,它也会影响 arrayOne ,对吗?

let arrayOne = [ '⚡️', '🔎', '🔑', '🔩' ];
let arrayOneSlice = arrayOne.slice(2, 3);  

// 更新 arrayOneSlice
arrayOneSlice[2] = '⚡️'

console.log(arrayOne); // [ '⚡️', '🔎', '🔑', '🔩' ]
console.log(arrayOneSlice); // [ '🔑', empty, '⚡️' ]

因为我们使用了方括号符号,Javascript把它解释为把一个新的值放到 [2] 的位置。所以只有 arrayOneSlice 被更新了。虽然 '🔑'arrayOne 中处于 [2] 的位置,但它在 arrayOneSlice 中处于 [0] 的位置。这可能会给人一种错觉,认为这两个数组是复制的,并且相互独立。 但事实也并非如此。考虑一下下面的例子。

let arrayOne = [  items: [ '🔎' ], '🔎', '🔑', '🔩' ];
let arrayOneSlice = arrayOne.slice(0, 3);  

// 更新 arrayOneSlice
arrayOneSlice[0].items = [ '⚡️' ]

console.log(arrayOne); // [  items: [ '⚡️' ], '🔎', '🔑', '🔩' ]
console.log(arrayOneSlice); // [  items: [ '⚡️' ], '🔎', '🔑' ]

在这里,我们更新了 arrayOneSlice[0].items,它在两个数组上都被更新了,因为 items 在两个数组的相同位置都存在,而且我们没有分配一个新的值,而是用点.符号来更新一个现有属性。在Javascript中,这同时更新了原始属性和我们用 slice 制作的副本。

对于浅层拷贝,需要记住的主要一点是,调整一个拷贝会影响你试图复制的原件。内存中的引用是相同的,而引用指向数组的值,所以你必须更加小心。你不想做的是产生意想不到的行为,即数组的原始和副本在你期望的时候没有同步更新。

那么,如何在Javascript中进行深度拷贝?

在深层拷贝方面,Javascript历来有一点问题。Javascript中的大多数方法,如三点扩展运算符语法、Object.create()、Object.assign()和Array.from(),都会进行浅层拷贝。

不过,深度拷贝在内存中有不同的引用,所以你不必担心在使用它们的时候会改变原件。这使得它们在我们想避免这种情况时非常有用。

深度拷贝可以通过序列化来实现,或者通过自定义脚本将一个对象或数组的每一部分复制到一个新的对象中,在内存中创建一个新的引用。例如,这将在Javascript中创建一个具有新引用的新数组。

let myArray = [ 1, 2, 3, 4 ];
let deepCopy = JSON.parse(JSON.stringify(myArray));

但这不一定是最好的方法。你也可以使用 structuredClone() 函数来做一个深度拷贝。

let myArray = [ 1, 2, 3, 4 ];
let deepCopy = structuredClone(myArray);

现在我们已经用深度拷贝创建了新的数组,我们不再需要担心在改变拷贝时弄乱了原始数组。

结论

浅层拷贝是相当令人困惑的,也是Javascript的众多怪癖之一。了解它们是什么,可以在将来调试时省去很多麻烦,而使用深度拷贝是避免这些问题的一个好办法。

javascript中的浅拷贝和深拷贝

浅拷贝:拷贝引用。拷贝后的新对象和源对象都是指向同一个引用地址,因此彼此之间操作互相影响。leta={num:1};letb=a;console.log(a===b);//truea.num=2;console.log(b.num);//2深拷贝:拷贝数据深拷贝后的新对象在对内存中重新分配内存空间,... 查看详情

javascript中的浅拷贝和深拷贝

...中都有浅拷贝和深拷贝的说法,这里简单区分一下它们在Javascript中的区别,以及jQuery中深拷贝的实现。在谈浅拷贝和深拷贝之前,先要屡清楚Javascript中的按值访问和按引用访问这两个概念。按值访问是针对基本类型(string、numb... 查看详情

javascript中的浅拷贝和深拷贝(代码片段)

谈这个话题特指javascript中的对象,我们使用赋值的语法来定义一个对象,其实只是获取了这个对象的引用letuser=name:"John";这里的user变量只是指向了对象,是对象的一个引用如果我们再定义一个变量,并且... 查看详情

C中的浅拷贝和深拷贝

】C中的浅拷贝和深拷贝【英文标题】:ShallowcopyanddeepcopyinC【发布时间】:2013-03-0717:49:31【问题描述】:我尝试用谷歌搜索,但只弹出面向对象的语言作为结果。据我了解,浅拷贝是复制结构的某些成员。所以我们说一个结构是t... 查看详情

浅谈js中的浅拷贝与深拷贝

  前端工程师应该都比较熟悉浅拷贝和深拷贝的概念,在日常业务代码的过程中,特别是做数据处理的时候,经常行的会遇到,比如如何在不修改原对象的基础上,重新生成一个一模一样的对象,加以利用,又或是,如何巧妙... 查看详情

javascript数组对象的浅拷贝与深拷贝深浅拷贝的区别+图解原理(代码片段)

JavaScript数组对象的浅拷贝和深拷贝知识回调(不懂就看这儿!)场景复现底层知识与原理1.关于内存(图解)2.关于数据类型3.关于赋值的原理深拷贝与浅拷贝浅拷贝实现原理(图解)深拷贝实现原理&#x... 查看详情

qimage的浅拷贝与深拷贝

 首先简单说说什么是浅拷贝和深拷贝:浅拷贝就比如像引用类型,而深拷贝就比如值类型,即浅拷贝是共用一块内存的,而深拷贝是复制一份内容。  我们再来看看QImage类的几个构造函数://浅拷贝QImage(uchar*data,intwidt... 查看详情

javascript浅拷贝与深拷贝(代码片段)

浅拷贝与深拷贝1. 什么是浅拷贝,深拷贝?2. 常用的浅拷贝方法2.1)'='赋值2.2)扩展运算符2.3)Object.assign()2.4)for...in3. 常用的深拷贝方法3.1)递归3.2)JSON做字符串转换1. 什么是浅拷贝,深拷贝?浅拷... 查看详情

pyhon的浅拷贝与深拷贝

...:创建一个新的组合对象,这个新对象与原对象共享内存中的子对象。3、深拷贝:创建一个新的组合对象,同时递归地拷贝所有子对象,新的组合对象与原对象没有任何关联。虽然实际上会共享不可变的子对象,但不影响它们... 查看详情

javascript|对象的拷贝

 javaScript|对象的拷贝上一遍是我们基本素组的拷贝,当然少不了我们对象的拷贝,当然也有我们的浅拷贝和我们的深拷贝滴啦;然后,深拷贝,从某个角度来说就是我们对象的继承;   对象拷贝分为浅拷贝(shallow)... 查看详情

objective-c中的深拷贝和浅拷贝

...内容原封不动的给我拿过来。对容器类的深拷贝是对容器中的每个元素都进行拷贝,容器类的浅拷贝是对容器里的内容不进行拷贝,两个容器的地址是不同的,但容器里的所装的东西是一样的,在一个 查看详情

javascript中的浅拷贝(代码片段)

1.什么是浅拷贝例如:根据原始A对象浅拷贝一个新的B对象出来浅拷贝就是创建一个新对象B,这个对象B有着原始对象A属性值的一份精确拷贝。如果属性是基本类型,拷贝的就是A对象的基本类型的值;如果属性是... 查看详情

js的浅拷贝和深拷贝

前言:对象的直接量赋值其实是一种引用,对赋值后的对象修改操作会影响到原始对象值,这里的其中包括object和Array。一、浅拷贝浅拷贝只是复制对象的一个指针,修改复制对象属性相当于修改原始对象的属性代码如下:functio... 查看详情

pytorch 数据加载器和/或 __getitem__ 函数中的浅拷贝和深拷贝

】pytorch数据加载器和/或__getitem__函数中的浅拷贝和深拷贝【英文标题】:shallowanddeepcopiesinpytorchdataloaderand/or__getitem__function【发布时间】:2022-01-1721:42:22【问题描述】:我在使用自定义pytorch数据加载器时遇到了问题,我认为这与... 查看详情

js对象的浅拷贝和深拷贝

..." }}varcopy=obj;copy.a="copy";console.log(obj.a)//"copy",可以看到这里的浅拷贝,会修改到原先的数据,因为浅拷贝是拷贝同一块内存块//es6有Object.assign()方法用于深度拷贝,不过只是一级深度拷贝varobj= 查看详情

javascript中的深拷贝和浅拷贝

文章目录JavaScript中的变量类型深拷贝和浅拷贝的理解深拷贝和浅拷贝的实现方式为什么需要深拷贝和浅拷贝 JavaScript中的变量类型(1)、基本类型  JavaScript中的基本类型有五种:null、undefined、boolean、string、number。变量是按... 查看详情

javascript中的深拷贝和浅拷贝到底是什么(代码片段)

前言:深拷贝和浅拷贝最根本的区别在于是否真正获取一个对象的复制实体,而不是引用。学习深拷贝和浅拷贝之前要先理解什么是基本类型和引用类型。一、到底什么是基本类型和引用类型?基本类型:就是值... 查看详情

c#的浅拷贝和深拷贝

在C++语法中我记得是这样规定的,浅拷贝只拷贝指向元素的引用,等同于只复制一份地址。该其一必定变其二,在C#语法中clone应该就是浅拷贝的,问题来了,..classProgramstaticvoidMain(string[]args)string[]str=newstring[]"ds","ewr&qu... 查看详情