浅拷贝和深拷贝的区别
一、数据类型
在讨论深浅拷贝之前,我们先说说数据类型,因为深浅拷贝与数据类型有关。
数据类型分为基本数据类型(String、Number、Boolean、Null、Undefined、Symbol (es6引入的一种类型) )和引用数据类型(Object、Array、Function)。
基本数据类型特点:直接存储在栈中;
引用数据类型:它真实的数据是存储在堆内存中,栈中存储的只是指针,指向在堆中的实体地址。
二、浅拷贝、深拷贝
深浅拷贝只是针对Array与Object这样的引用数据类型。简单来说,浅拷贝只是拷贝了它在栈中存储的指针,它们指向的都是同一个堆内存地址,所以浅拷贝在某些情况会造成改变数据后导致别的另一份数据也同步被改变的情况;而深拷贝是直接将堆内存中存储的数据直接复制一份,不会有浅拷贝互相影响的问题。
三、浅拷贝的方法
1. Object.assign()
从上面的例子我们发现,用Object.assign()实现的浅拷贝,当拷贝对象中的字段第一层的值为基础数据类型(如上面的a的值是个字符串,“a1”),那是不会被同步影响的;如果第一层的值还包含子对象(如上面b的值就是个对象,还包含了name字段),那就会被影响。所以如果被复制的object的每个字段第一层都是基础数据类型,那就是深拷贝。
2. Array.prototype.concat()
3. Array.prototype.slice()
2和3的方式效果与1一样,都是第一层的值为基础数据类型不会被同步影响,否则就会。
四、深拷贝的方法
1. JSON.parse(JSON.stringify())
将一个对象先转为json字符串,然后再转回来,这样可以实现深拷贝。
但是这个方法有个缺陷,可以实现对象或数组的深拷贝,但是不能处理函数,函数经过这样处理后会变成null。
所以比较推荐的方法是:
1. 递归的方法,遍历要克隆的每个字段,发现它的值是对象或数组后继续递归。
function clone(target) { let res = undefined; if (Object.prototype.toString.call(target) === '[object Object]') { res = {}; } else if (Object.prototype.toString.call(target) === '[object Array]') { res = []; } else { return target; } for (let key in target) { let value = target[key]; if (Object.prototype.toString.call(value) === '[object Object]' || Object.prototype.toString.call(value) === '[object Array]') { res[key] = clone(value); } else { res[key] = value; } } return res; } let a = [1,2,3,{ a: "a1", b: { name: "张三" } }] let b = clone(a) b[3].b.name = "我是b" console.log(a,b)
2. 比较推荐的方法,引用lodash依赖,使用里面的cloneDeep()方法
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· [.NET]调用本地 Deepseek 模型
· 一个费力不讨好的项目,让我损失了近一半的绩效!
· .NET Core 托管堆内存泄露/CPU异常的常见思路
· PostgreSQL 和 SQL Server 在统计信息维护中的关键差异
· C++代码改造为UTF-8编码问题的总结
· 【.NET】调用本地 Deepseek 模型
· CSnakes vs Python.NET:高效嵌入与灵活互通的跨语言方案对比
· DeepSeek “源神”启动!「GitHub 热点速览」
· 我与微信审核的“相爱相杀”看个人小程序副业
· Plotly.NET 一个为 .NET 打造的强大开源交互式图表库