最近有一位00后的小妹妹粉丝私信小编说自己很喜欢编程,目前在某公司实习前端开发工作,说到现在为止还没有搞懂JAVAScript中深拷贝和浅拷贝这个问题,同时也在网上看了很多关于深拷贝的文章,但是质量良莠不齐,有很多都考虑得不周到,写的方法比较简陋,难以令人满意,理解的迷迷糊糊 。让小编深入剖析JavaScript中深浅拷贝 。
看这位小姑娘如此的好学,不懂就问的这种精神可嘉,小编非常佩服 。仿佛看见当年自己好学的影子了 。在这里给她点赞 。
对于深拷贝和浅拷贝这个问题,相信大家都遇到过,那么怎么区分深拷贝和浅拷贝这个问题呢?
往简单了理解,就是一句话概括:假设有一个变量A,变量B复制了变量A,如果我们修改变量A,看变量B是否会发生改变,如果改变了,那么就是浅拷贝,如果变量A值的变化不影响B,那么就是深拷贝,估计用文字说这么多,可能大家都会看懵了 。
先概念介绍
- 深拷贝:在堆内存中重新开辟一个存储空间,完全克隆一个一模一样的对象;
- 浅拷贝:不在堆内存中重新开辟空间,只复制栈内存中的引用地址 。
还看不懂的话,看下图:

文章插图
JavaScript中浅拷贝浅拷贝: 创建一个新的对象,来接受你要重新复制或引用的对象值 。如果对象属性是基本的数据类型,复制的就是基本类型的值给新对象;但如果属性是引用数据类型,复制的就是内存中的地址,如果其中一个对象改变了这个内存中的地址所指向的对象,肯定会影响到另一个对象 。
首先我们看看一些浅拷贝的方法,如下图:

文章插图
JavaScript中浅拷贝
这里只列举了常用的几种方式,除此之外当然还有其他更多的方式 。注意,我们直接使用=赋值不是浅拷贝,因为它是直接指向同一个对象了,并没有返回一个新对象 。
手动实现一个浅拷贝:
function shallowClone(target) {if (typeof target === 'object' && target !== null) {const cl.NETarget = Array.isArray(target) ? [] : {};for (let prop in target) {if (target.hasOwnProperty(prop)) {cloneTarget[prop] = target[prop];}}return cloneTarget;} else {return target;}}// 测试const shallowCloneObj = shallowClone(obj)shallowCloneObj === obj// false,返回的是一个新对象shallowCloneObj.arr === obj.arr// true,对于对象类型只拷贝了引用从上面这段代码可以看出,利用类型判断(查看typeof),针对引用类型的对象进行 for 循环遍历对象属性赋值给目标对象的属性(for...in语句以任意顺序遍历一个对象的除Symbol以外的可枚举属性,包含原型上的属性 。查看for…in),基本就可以手工实现一个浅拷贝的代码了 。JavaScript中深拷贝在日常开发中,深拷贝是一个常见需求,我们可以通过 JSON 转换、递归、 Lodash _.cloneDeep() 等方式实现 。下面小编一一深入剖析
第一种:递归方式(推荐,项目中最安全最常用)使用递归的方式进行对象(数组)的深拷贝,奉上已封装的深拷贝函数:
上方函数的使用方式:
//函数拷贝const copyObj = (obj = {}) => {//变量先置空let newobj = null;//判断是否需要继续进行递归if (typeof (obj) == 'object' && obj !== null) {newobj = obj instanceof Array ? [] : {};//进行下一层递归克隆for (var i in obj) {newobj[i] = copyObj(obj[i])}//如果不是对象直接赋值} else newobj = obj;return newobj;}上方函数的使用方式://模拟对象let obj = {numberParams:1,functionParams:() => {console.log('欢迎关注 Echa工程师');},objParams:{a:1,b:2}}const newObj = copyObj(obj); //这样就完成了一个对象的递归拷贝obj.numberParams = 100;//更改第一个对象的指console.log(newObj.numberParams); //输出依然是1 不会跟随obj去改变第二种:JSON.stringify() ;(这个不推荐使用,有坑)这个方法有坑,详细讲解请看我另一篇文章 “使用JSON.stringify进行深拷贝的坑” 以下是代码示例:let obj = {a:1,b:"来今日头条,欢迎关注 Echa工程师 。后面会不定期更新干货和技术相关的资讯推荐"}//先转为json格式字符,再转回来let newObj = JSON.parse(JSON.stringify(obj));obj.a = 50;console.log(newObj.a); //输出 1普通的对象也可以进行深拷贝,但是!!!当对象内容项为 number、string、boolean的时候,是没有什么问题的 。但是,如果对象内容项为undefined、null、Date、RegExp、function,error的时候 。使用JSON.stringify()进行拷贝就会出问题了 。
推荐阅读
- 5个等级的数据分析,哪个最深入?
- 最流行的 WebAssembly 语言,会是 JavaScript 吗?
- 人际关系|深入解析职场沟通:概念、类型和重要性
- |男性管理者职场历程剖析:担任正科15年还有机会晋升副处级吗?
- 2023年,Rust能干掉JavaScript吗?
- JS混淆加密应用场景有哪些?
- JavaScript日期处理不再难!Day.js带你飞!
- 饵料|有效解决杂鱼闹窝的方法剖析!敢于诱鱼,善于总结你就是高手!
- 深入探究Java IO流:基础知识、流类型及使用方法
- 深入理解Java中hashCode的作用
