JavaScript中的浅拷贝与深拷贝
前言
JavaScript中的浅拷贝和深拷贝是非常重要的概念,它们在处理对象和数组时具有不同的作用。在编程中,经常需要复制数据以便进行各种操作,但必须注意拷贝的方式,以确保得到预期的结果。
浅拷贝是创建一个新对象或数组,并将原始对象或数组的引用复制给它。这意味着新对象和原始对象将共享相同的内存地址,修改其中一个对象的属性或元素也会影响另一个对象。相反,深拷贝是创建一个完全独立的对象或数组,新的拷贝将具有与原始对象或数组相同的值,但是它们在内存中是彼此独立的,相互之间的修改不会互相影响。
本文小编将为大家介绍JavaScript中实现浅拷贝和深拷贝的不同方法,并提供示例代码作为辅助。
基本拷贝
下面是一个基本的拷贝,新的拷贝对象会专门开辟一块内存空间——二者的类型、值都是独立可变的,换句话说,他们是通过将值传递给新对象完成拷贝的。
//原始值拷贝
let x = 400
let y = x
x = "This string"
console.log(y) //400
console.log(x) //This string
当y被创建时,它的值被赋予了x的值(因为这是在运行时,x被重新赋值之前)。这里重要的一点是,读者可以通过创建另一个变量并将其分配给要复制的变量来快速将原始数据类型的精确值复制到单独的内存空间中。请注意它是如何实例化的——const 不允许再进行更改。

(内存分配和原始赋值的视觉进展)
//小编可以走的更深一些,在上面的代码中,再将x设置为原始数据类型;
//当然了,小编都知道它们是在不同的内存空间,只不过值是相同的
let x = 400
let y = x
x = "This string"
console.log(y) //400
console.log(x) //This string
x = 400
console.log(x) // 400
console.log(y) // 400
浅拷贝
以下是一个展示浅拷贝的示例。在此示例中,拷贝了一个包含文字的浅对象。由于浅拷贝只会复制原始对象的引用而非值本身,所以被拷贝的对象和原始对象将共享相同的内存空间,即它们的值也将相同。需要注意的是,在 JavaScript 中,“浅对象”是指一种非嵌套且非原始的 JavaScript 数据类型。
// 浅对象的浅拷贝
let ShallowObj= {
key1: 1,
key2: 2,
}
let newObj = ShallowObj// 一个简单的重新分配为 newObj 创建共享内存
ShallowObj.key1 = 5
console.log(shallowObj) // {key1: 5, key2: 2}
console.log(newObj) // {key1: 5, key2: 2}
当重新分配ShallowObj中key1的值时,会导致newObj中key1的值也随之发生改变。尽管这两个对象具有不同的变量名称,但它们实际上共享相同的内存空间。因此,如果需要更改shallowObj.key1的值,可以直接修改newObj.key1来获得相同的结果。这在某些情况下非常有用,例如当需要表示一组具有相同属性和值的特定对象时。然而,在运行时,可能需要给这些浅拷贝对象赋予不同的变量名称,以满足应用程序的需求,并作为不同的props传递给其他组件。通过使用不同的变量名称,可以根据不同的目标在应用程序中对它们进行独立操作,以实现所需的功能。
对浅对象进行深拷贝
//使用 Object.assign()
let myRadio = { podcasts: 19,
albums: 378,
playlists: 44
}
let deepCopyMyRadio = Object.assign( {}, myRadio )
deepCopyMyRadio.playlists = 62 // 只改变 deepCopyMyRadio
console.log(deepCopyMyRadio) // => { podcasts: 19,
albums: 378,
playlists: 62
}
console.log(myRadio) // => { podcasts: 19,
albums: 378,
playlists: 44
}
ES6引入了一种新特性称为扩展运算符。扩展运算符用三个连续的点"..."表示,并可以在代码的多个地方使用。通常情况下,扩展运算符会为给定对象的每个顶级属性创建副本,并将它们扩展到新对象中。在特定情况下,可以选择使用浅拷贝或深拷贝来处理嵌套对象。在本例中,展示的是浅对象的深拷贝,因此可以使用Object.assign()方法或以下示例即可。
//用扩展运算符深拷贝
let myRadio = { podcasts: 9,
albums: 38,
playlists: 4
}
let copyMyRadio = { ...myRadio }
myRadio.albums = 88 // 还是只改变myRadio
console.log(myRadio) //=> { podcasts: 9, albums: 88, playlists: 4 }
console.log(copyMyRadio) //=> {podcasts: 9,albums: 38, playlists: 4}
不过这种写法的问题在于,随着项目规模和复杂性的增加,扩展运算符是一个有局限的解决方案。扩展运算符可以处理浅对象的深拷贝(非嵌套),即将一个对象的顶级属性复制到另一个对象中。然而,当涉及嵌套对象或多层级结构时,扩展运算符会遇到限制。它只能复制对象的第一层属性,而无法递归地复制嵌套的对象。

(分配方式:someOtherVar = someVar)
下面我们来看一下展开运算符在处理嵌套对象的复杂性时,并不如预期。对于嵌套对象来说,扩展运算符只提供了第一层属性的深拷贝,而对于所有嵌套的数据来说,它们与原始数据共享内存空间,实际上进行的是浅拷贝。

Population.total 在 city 和shallowCity 中共享一个内存点。扩展运算符获取顶层数据并将其添加到单独的内存空间;因此,shallowCity 的 name 属性实际上已更改。
对深对象进行深拷[JSON.parse(JSON.stringify())]
为了解决嵌套对象的复杂性问题,下面向大家介绍如何在深对象中进行深拷贝。在 JavaScript 中,当需要复制嵌套对象或数组时,深拷贝变得非常重要。深拷贝是一种创建独立全新对象的方法,它递归地复制每个嵌套对象和数组,有效地避免了使用共享内存带来的修改问题。其中,最常用的深拷贝方法是使用JSON.parse(JSON.stringify(object))。该方法首先将原始对象序列化为 JSON 字符串,然后再解析字符串并创建一个新对象,以确保所有属性和嵌套对象都被复制到全新的对象中。当然,需要注意的是该方法存在一定的局限性,例如无法复制函数、正则表达式等非数据类型,并且在某些情况下可能会带来性能问题。因此,在实际应用中,我们必须根据具体情况选择适合的深拷贝方法,以取得效率和正确性的平衡。

(对深对象进行深拷贝)
总结
JavaScript中的浅拷贝复制对象是创建一个新对象,但嵌套对象仍然共享内存。而深拷贝则创建一个独立的全新对象,包括嵌套对象在内都被完全复制。浅拷贝常用方法有Object.assign()和扩展运算符,而深拷贝可以使用JSON.parse(JSON.stringify())或第三方库。深拷贝适用于修改副本且不影响原始对象的情况,但可能消耗更多资源和时间。了解这两种拷贝方式的差异和应用场景是编写健壮代码的关键。
JavaScript中的浅拷贝与深拷贝的更多相关文章
- Javascript中的浅拷贝和深拷贝
很多开发语言中都有浅拷贝和深拷贝的说法,这里简单区分一下它们在Javascript中的区别,以及jQuery中深拷贝的实现. 在谈浅拷贝和深拷贝之前,先要屡清楚Javascript中的按值访问和按引用 ...
- javascript中的浅拷贝和深拷贝(拷贝引用和拷贝实例)
作者:千锋教育链接:https://www.zhihu.com/question/23031215/answer/326129003来源:知乎著作权归作者所有.商业转载请联系作者获得授权,非商业转载请 ...
- javascript中的浅拷贝和深拷贝 分类: JavaScript 2015-05-07 15:29 831人阅读 评论(1) 收藏
1.js对象浅拷贝 简单的赋值就是浅拷贝.因为对象和数组在赋值的时候都是引用传递.赋值的时候只是传递一个指针. 看下面的实例代码: var a = [1,2,3]; var b =a ; var te ...
- 【转】JAVA中的浅拷贝和深拷贝
原文网址:http://blog.bd17kaka.net/blog/2013/06/25/java-deep-copy/ JAVA中的浅拷贝和深拷贝(shallow copy and deep co ...
- javascript中的堆栈、深拷贝和浅拷贝、闭包
堆栈 在javascript中,堆内存是用来存放引用类型的空间环境 而栈内存,是存储基本类型和指定代码的环境 在对象中的属性名具有唯一性,数字属性名=字符串属性名,但是在测试的时候你会发现,好像所有属 ...
- javascript中的浅拷贝ShallowCopy与深拷贝DeepCopy
拷贝,在js中,分为浅拷贝和深拷贝.这两者是如何区分的呢?又是如何实现的呢? 深浅拷贝的区分 首先说下,在js中,分为基础数据类型和复杂数据类型, 基础数据类型:Undefined.Null.Bool ...
- js中的浅拷贝和深拷贝
说说最近所学:浅拷贝和深拷贝也叫做浅克隆和深克隆,深浅主要针对的是对象的"深度",常见的对象都是"浅"的,也就是对象里的属性就是单个的属性,而"深&q ...
- 浅谈JS中的浅拷贝与深拷贝
前端工程师应该都比较熟悉浅拷贝和深拷贝的概念,在日常业务代码的过程中,特别是做数据处理的时候,经常行的会遇到,比如如何在不修改原对象的基础上,重新生成一个一模一样的对象,加以利用,又或是,如何巧妙地运 ...
- C# 中的浅拷贝与深拷贝
Ø 简介 在 C# 中分为两种数据类型,值类型和引用类型.我们知道,值类型之间赋值是直接将值赋值给另一个变量,两个变量值的改变都互不影响:而引用类型赋值则是将引用赋值给另一个变量,其中一个变量中的成 ...
- Javascript/js 的浅拷贝与深拷贝(复制)学习随笔
js变量的数据类型值分基本类型值和引用类型值. 在ES6(ECMAScript6)以前,基本数据类型包括String.Number.Boolean.Undefined.Null. 基本类型值的复制(拷 ...
随机推荐
- python里class(类)中object是什么意思
python的class(类)中的object是什么意思? 写object和不写object有什么区别? 示例代码 class Test: name = "libai" class ...
- Java如何实现去重?这是在炫技吗?
大家好,我3y啊.由于去重逻辑重构了几次,好多股东直呼看不懂,于是我今天再安排一波对代码的解析吧.austin支持两种去重的类型:N分钟相同内容达到N次去重和一天内N次相同渠道频次去重. Java开源 ...
- 原来kafka也有事务啊,再也不担心消息不一致了
前言 现在假定这么一个业务场景,从kafka中的topic获取消息数据,经过一定加工处理后,发送到另外一个topic中,要求整个过程消息不能丢失,也不能重复发送,即实现端到端的Exactly-Once ...
- 公路堵车概率模型Python(Nagel-Schreckenberg交通流模型)
路面上有N辆车,以不同速度向前行驶,模拟堵车问题.有以下假设: 假设某辆车的当前速度是 v 如果 前方可见范围内没车,下一秒车速提高到 v+1 如果 前方有车,前车的距离为 d ,且 d < v ...
- 【Promptulate】一个强大的LLM Prompt Layer框架
本文节选自笔者博客: https://www.blog.zeeland.cn/archives/promptulate666 前言 在构建了[prompt-me]一个专为 Prompt Enginee ...
- RSA 加密签名验签解密
import javax.crypto.Cipher; import javax.crypto.spec.OAEPParameterSpec; import javax.crypto.spec.PSo ...
- MyBatis实现动态SQL更新
博主记得在一个周五快下班的下午,产品找到我(为什么总感觉周五快下班就来活 ),跟我说有几个业务列表查询需要加上时间条件过滤数据,这个条件可能会变,不保证以后不修改,这个改动涉及到多个列表查询,于是博主 ...
- Matlab背景颜色修改
背景 将修改内容添加到matlab的matlab.prf文件中,文件路径为在matlab中运行prefdir的结果,直接添加这些内容保存就好. github主题制作地址,里面有多种matlab主题配色 ...
- HTTP&HTTPS协议
HTTP协议 1.什么是HTTP 超文本传输协议( HyperText Transfer Protoco,缩写:HTTP)是一种用于分布式.协作式和超媒体信息系统的应用层协议. HTTP(HyperT ...
- kbuild系统中最简单的目标 -- help(三)
当你学完help目标后你会发现它与我们的代码基本没有什么直接的关系,仅仅是用来生成kbuild的简短使用说明,但是用它来作为学习掌握kbuild编译系统的开篇,不管是从难度还是学习感受上真的是再适合不 ...