深拷贝、浅拷贝及其实现方式
文章目录
- 一、浅拷贝
- 二、深拷贝
- 三、判断深、浅拷贝
- 1.concat()方法
- 2.slice()方法
- 3.Array.from()方法
- 4.扩展运算符
- 四、实现浅拷贝
- 1.Object.assign方法
- 2.for in方法
- 五、实现深拷贝
- 1.递归实现
- 2.JSON.stringify与JSON.parse
- 3.loadash函数库
一、浅拷贝
浅拷贝和深拷贝都只针对于引用数据类型,浅拷贝只复制指向某个对象的指针,而不复制对象本身,新旧对象还是共享同一块内存;
例如:
const obj_1 = {age: 21
}
const obj_2 = obj_1; // 对象obj_2只复制了obj_1的地址
obj_2.age = 19;
console.log(obj_1.age); // 输出:19
内存角度:对象obj_1会在栈中分配一个内存地址,该内存地址对应的值又会创建一个新的内存地址,该新的内存地址又指向堆这样一个数据结构,并在堆中创建对应的属性值age:21。而上述案例中创建obj_2并赋值obj_1,实际上只复制了指针,这么做将会导致obj_2与obj_1指向同一个地址,他们两从栈到堆这两种数据类型的链路都是一样的,obj_2修改属性age的值,导致obj_1中age的值发生改变,称作只实现了浅拷贝。
二、深拷贝
不同于浅拷贝,深拷贝会另外创造一个一模一样的对象,新对象跟原对象不共享内存,修改新对象不会改到原对象;
三、判断深、浅拷贝
我们通过我们熟知的引用类型——数组,用其内置的一些方法判断是浅拷贝还是深拷贝
1.concat()方法
判断:
let list = ['我爱', '学习'];
let copyList = [].concat(list);
copyList.push('JavaScript');
console.log(list); // ['我爱', '学习']
console.log(copyList); // ['我爱', '学习', 'JavaScript']
我们使用concat()方法拷贝副本,返回新构建的数组,此时我对新数组元素的添加也不会影响到原数组,然而。。。答案为:浅拷贝
2.slice()方法
判断:
let list = ['我爱', '学习'];
let copyList = list.slice();
copyList.push('JavaScript');
console.log(list); // ['我爱', '学习']
console.log(copyList); // ['我爱', '学习', 'JavaScript']
我们使用slice()方法不传参的方式从头到尾拷贝副本,并且返回新数组,即使我对新数组添加元素也不会影响到原数组,然而。。。答案仍然为:浅拷贝
3.Array.from()方法
判断:
let list = ['我爱', '学习'];
let copyList = Array.from(list);
copyList.push('JavaScript');
console.log(list); // ['我爱', '学习']
console.log(copyList); // ['我爱', '学习', 'JavaScript']
我们使用ES6中Array.from()方法同样以不影响原数组的方式实现了拷贝,然而。。。答案依旧为:浅拷贝
4.扩展运算符
判断:
let list = ['我爱', '学习'];
let copyList = [...list];
copyList.push('JavaScript');
console.log(list); // ['我爱', '学习']
console.log(copyList); // ['我爱', '学习', 'JavaScript']
我们再次使用ES6中扩展运算符,同理:浅拷贝
我们来考证一下:
let list = [{ name: 'Tom' }];
let copyList = [...list];
copyList[0].name = 'Jerry'
console.log(list[0].name); // Jerry
console.log(copyList[0].name); // Jerry
我们将数组元素都换成引用类型,执行以上方法,并通过拷贝副本改变数组元素的值,我们会发现原数组的元素也发生了改变,由此可见,确实是浅拷贝。除此之外,数组的其他方法如map()、filter()、reduce(),都是会造成浅拷贝的。
四、实现浅拷贝
1.Object.assign方法
let list = {obj: {hobby: 'JavaScript'}
}
let copyList = Object.assign({}, list);
copyList.obj.hobby = 'Vue'
console.log(list.obj.hobby); // Vue
2.for in方法
let user1 = {name: "小明",age: 30,height: 1.9,hobby: {project: 'React'}
};
let user2 = {};
for (let i in user1) {user2[i] = user1[i]; //user1[i]输出的是每一个属性的值,将user1的每一个属性的值取出来赋值给user2对象
}
user2.name = '小蓝'
user2.hobby.project = 'Vue'
console.log(user1) //{ name: "小明", age: 30, height: 1.9, hobby: { project: 'Vue' } }
五、实现深拷贝
1.递归实现
采用递归去拷贝所有层级属性
function deepClone(obj) {let objClone = Array.isArray(obj) ? [] : {};if (obj && typeof obj === "object") {for (key in obj) {if (obj.hasOwnProperty(key)) {//判断ojb子元素是否为对象,如果是,递归复制if (obj[key] && typeof obj[key] === "object") {objClone[key] = deepClone(obj[key]);} else {//如果不是,简单复制objClone[key] = obj[key];}}}}return objClone;
}
let a = [1, 2, 3, 4],b = deepClone(a);
a[0] = 2;
console.log(a, b) // [2,2,3,4] [1,2,3,4]
2.JSON.stringify与JSON.parse
通过JSON.stringify把对象转成字符串,再用JSON.parse把字符串转成一个全的新的对象;
let list = [{ name: 'Tom' }];
let copyList = JSON.parse(JSON.stringify([...list]));
copyList[0].name = 'Jerry'
console.log(list[0].name); // Tom
console.log(copyList[0].name); // Jerry
3.loadash函数库
函数库lodash,也有提供_.cloneDeep用来做深拷贝
let lodash = require('lodash');
let list = [{ name: 'Tom' }];
let copyList = lodash.cloneDeep(list);
copyList[0].name = 'Jerry'
console.log(list[0].name); // Tom
console.log(copyList[0].name); // Jerry
深拷贝、浅拷贝及其实现方式相关推荐
- 一篇文章彻底说清JS的深拷贝/浅拷贝
一篇文章彻底说清JS的深拷贝and浅拷贝 这篇文章的受众 第一类,业务需要,急需知道如何深拷贝JS对象的开发者. 第二类,希望扎实JS基础,将来好去面试官前秀操作的好学者. 写给第一类读者 你只需要一 ...
- 对象克隆-深拷贝,浅拷贝,直接赋值
1背景分析 在 Java 开发中,对象拷贝或者说对象克隆是常有的事,对象克隆最终都离不开直接赋值.浅拷贝.深拷贝 这三种方式,我们常用的对象的转化方式,使用的是spring的 BeanUtils.co ...
- java深拷贝和浅拷贝_Java 深拷贝浅拷贝 与 序列化
一.浅拷贝.深拷贝 浅拷贝会对对象中的成员变量进行拷贝:如果是基本类型,拷贝的就是基本类型的值:如果属性是内存地址(引用类型),拷贝的就是内存地址 : 深拷贝,除了基本类型外,引用类型所引用的对象也会 ...
- Java基础 深拷贝浅拷贝
Java基础 深拷贝浅拷贝 非基本数据类型 需要new新空间 class Student implements Cloneable{private int id;private String name ...
- 原型模式与深拷贝浅拷贝
原型模式与深拷贝浅拷贝 原型模式 Java中的原型模式 简单的例子 浅拷贝 深拷贝 效率比较 JMH测试样例 测试结果 原型模式 用一个已经创建的实例作为原型,通过复制该原型对象来创建一个和原型相同或 ...
- 超级全面-深拷贝与浅拷贝的实现方式
一.数据类型: (1)基本数据类型:number,string,Boolean,null,undefined,symbol(ES6),BigInt(ES10): (2)引用数据类型:对象,数组,函数等 ...
- Map的putAll方法踩坑实记(对象深拷贝浅拷贝)
文章目录 问题描述 编写测试代码模拟问题场景 场景1:Map中不包含对象 场景2:Map中包含对象 什么是对象的浅拷贝深拷贝 如何实现深拷贝 问题描述 在一个产品管理系统中,产品信息需要封装一份同步业 ...
- JavaScript学习笔记(五)--深拷贝浅拷贝
如何区分深拷贝与浅拷贝,简单点来说,就是假设B复制了A,当修改A时,看B是否会发生变化,如果B也跟着变了,说明这是浅拷贝,拿人手短,如果B没变,那就是深拷贝,自食其力. 本篇文章中也会简单阐述到栈堆, ...
- java深拷贝的三种方式
问题:spring boot/JPA项目中,修改某个对象以后需要生成一个VO对象给客户端,数据库对应的POJO对象里有个Map类型的对象(名字叫para),这个对象的value又是个Map,我使用Ma ...
最新文章
- Asp.Net MVC 4 Web API 中的安全认证-使用OAuth
- 中华成语故事摄制组大公无私的释义
- activeMq 安装
- IDEA 启动 Tomcat 乱码 解决办法
- 计算机机等级考试四级模拟,《全国计算机等级考试上机考试模拟考场-四级》.pdf...
- rs232读取智能电表_没想到物联网电表这么智能!插卡预付费电表该升级了!
- input数字开头不能为0_李商隐为初恋写诗,每句以数字开头,最后10字一直被仿从未被超越...
- 每天五个java相关面试题(3)
- android bitmap oom 最新处理办法,【移动开发】Android中图片过大造成内存溢出,OOM(OutOfMemory)异常解决方法...
- java shapefile 中文乱码_GeoTools操作Shape格式文件
- java的IO操作之--RandomAccessFile
- 主数据——共享数据的核心,数据资产的灵魂
- Button按钮四种监听(二)及实例
- Java实现各种加密验证算法(MD5、SHA256、base64、pdkdf2、pdkdf2_sha256)
- 计算机图形学--全局光照(屏幕空间:SSDO,SSR)
- 讲座笔记 | 批判性思维和论文写作
- 一台 ZXHN F650(GPON ONU) 学习小记
- 最通俗易懂的JUC多线程并发编程
- 三星会在泰泽大会上展示meego系统的新机么?
- YAPI简单使用教程