经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » Java相关 » Java » 查看文章
【JavaScript】js中的浅拷贝与深拷贝与手写实现
来源:cnblogs  作者:我恨bug  时间:2024/7/13 18:26:29  对本文有异议

前言

什么是深拷贝与浅拷贝?深拷贝与浅拷贝是js中处理对象或数据复制操作的两种方式。?在聊深浅拷贝之前咱得了解一下js中的两种数据类型:

基本数据类型(6种)
String、Number、Object、Boolean、null、undefined、symbol(ES6+)

引用数据类型
Object(function、Array、正则表达式等皆是对象)

  • 数据的存储方式是什么?

基本数据: 基本数据类型是存放在栈中的简单数据段,它们是直接按值存放的,所以可以直接按值访问
引用类型: 引用类型是存放在堆内存中的对象,保存的在栈内存中的一个指针,保存的是栈内存中对象在堆内存中的引用地址。通过这个引用地址可以快速查找到保存中堆内存中的对象。

1.浅拷贝

1.1 什么是浅拷贝

浅拷贝,指的是创建新的数据,这个数据有着原始数据属性值的一份精确拷贝。如果属性是基本类型,拷贝的就是基本类型的值。如果属性是引用类型,拷贝的就是内存地址即浅拷贝是拷贝一层,深层次的引用类型则共享内存地址。

  • 下面用一张图来解释一下浅拷贝
    image

1.2 浅拷贝实现方法

1.2.1 assign

  1. var obj = {
  2. age: 18,
  3. person: {
  4. name1: 'fx',
  5. name2: 'xka'
  6. },
  7. list:['hhh','666'],
  8. love: function () {
  9. console.log('嘿嘿')
  10. }
  11. }
  12. var newObj = Object.assign({}, obj);
  13. //因为是浅拷贝,所以只拷贝了基本类型的,引用类型还是共享内存地址的,即改变obj的应用类型的内容,newObj里面的引用类型的值也随之改变
  14. obj.person.name1='xxx'
  15. obj.list[0]='xxx'
  16. console.log(newObj.person.name1) //xxx

1.2.2 slice

  1. const fxArr = ["One", {
  2. name: "Two",
  3. age: 20
  4. }, "Three"]
  5. const fxArrs = fxArr.slice(0,)
  6. fxArr[1].name = "four";
  7. console.log(fxArrs[1].name) //four

1.2.3 concat

  1. const fxArr = ["One", {
  2. name: "Two",
  3. age: 20
  4. }, "Three"]
  5. const fxArrs = fxArr.concat()
  6. fxArr[1].name = "four";
  7. console.log(fxArrs[1].name) //four

1.2.4 拓展运算符

  1. const fxArr = ["One", {
  2. name: "Two",
  3. age: 20
  4. }, "Three"]
  5. const fxArrs = [...fxArr]
  6. fxArr[1].name = "four";
  7. console.log(fxArrs[1].name) //four

2.深拷贝

2.1 什么是深拷贝

深拷贝开辟一个新的栈,两个对象属完成相同,但是对应两个不同的地址,修改一个对象的属性,不会改变另一个对象的属性

  • 下面用一张图来解释一下深拷贝
    image

2.2 浅拷贝实现方法

2.2.1 JSON.parse(常用)

  1. var obj = {
  2. age: 18,
  3. person: {
  4. name1: 'fx',
  5. name2: 'xka'
  6. },
  7. list:['hhh','666'],
  8. love: function () {
  9. console.log('嘿嘿')
  10. }
  11. }
  12. const obj2=JSON.parse(JSON.stringify(obj));
  13. obj.person.name1='6666'
  14. console.log(obj2.person.name1) //fx
  • 我常用的基本就是JSON.parse了,然而其他的,之前听过的lodash的cloneDeep,jq的extend我都没使用过。

3.手写实现深浅拷贝

3.1 浅拷贝

  1. function clone(object){
  2. const newObj={}
  3. for(let proto in object){
  4. if(object.hasOwnProperty(proto)){
  5. newObj[proto]= object[proto]
  6. }
  7. }
  8. return newObj
  9. }
  1. var obj = {
  2. age: 18,
  3. person: {
  4. name1: 'fx',
  5. name2: 'xka'
  6. },
  7. list:['hhh','666'],
  8. love: function () {
  9. console.log('嘿嘿')
  10. }
  11. }
  12. const obj1=clone(obj)
  13. console.log(obj)
  14. console.log(obj1)

3.2 深拷贝

  1. // 手写深拷贝
  2. function deepClone(obj, hash = new WeakMap()) {
  3. // 数据过滤
  4. if (obj === null) return obj; // 如果是null或者undefined我就不进行拷贝操作
  5. if (obj instanceof Date) return new Date(obj);// 如果传入的对象是日期对象,使用 new Date() 创建一个新的日期对象并返回
  6. if (obj instanceof RegExp) return new RegExp(obj);// 如果传入的对象是正则表达式对象,使用 new RegExp() 创建一个新的正则表达式对象并返回
  7. // 如果传入的对象不是普通对象(即不是对象类型)或普通的值 如果是函数的话就不需要深拷贝
  8. // 因为拷贝的只需要考虑是否为对象,所以只需要判断obj是否为对象类型即可,因为null或者undefined在上面已经先过滤掉了,此时就只剩下基本数据类型和函数了
  9. if (typeof obj !== "object") return obj;
  10. // 来到此处的话就只剩下对象了,就要进行深拷贝
  11. if (hash.get(obj)) return hash.get(obj);
  12. // 深拷贝
  13. // 创建一个新对象,这个新对象和obj对象类型相同
  14. // 找到的是所属类原型上的constructor属性,而原型上的constructor指向的是当前类本身
  15. let cloneObj = new obj.constructor();
  16. hash.set(obj, cloneObj);
  17. for (let key in obj) {
  18. if (obj.hasOwnProperty(key)) {
  19. // 实现一个递归拷贝
  20. cloneObj[key] = deepClone(obj[key], hash);
  21. }
  22. }
  23. return cloneObj;
  24. }
  1. var obj = {
  2. age: 18,
  3. person: {
  4. name1: 'fx',
  5. name2: 'xka'
  6. },
  7. list:['hhh','666'],
  8. love: function () {
  9. console.log('嘿嘿')
  10. }
  11. }
  12. const obj2 = deepClone(obj) // 深拷贝
  13. const obj3 = Object.assign({}, obj) // 浅拷贝
  14. const obj4 = clone(obj) // 浅拷贝
  15. obj.person.name1 = 'hhh';
  16. //因为是深拷贝,obj2中的引用类型新开辟了一个内存地址,所以obj的person改变obj2不受影响
  17. console.log(obj2.person.name1) //fx
  18. //因为是浅拷贝,obj3、obj4中的引用类型与obj中的引用类型共享内存地址,所以obj的person改变obj3、obj4皆受影响
  19. console.log(obj3.person.name1) //hhh
  20. console.log(obj4.person.name1) //hhh

上述为个人学习整理内容,水平有限,如有错误之处,望各位园友不吝赐教!如果觉得不错,请点击推荐和关注!谢谢~??????? [鲜花][鲜花][鲜花]

原文链接:https://www.cnblogs.com/nothavebug/p/18300473

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号