深拷贝和浅拷贝

痛定思痛。 2022-10-01 04:56 377阅读 0赞

参考文章: www.cnblogs.com/echolun/p/7…

www.jianshu.com/p/2188dcd91…

由于基本数据类型存储在栈内存中,

他们有各自不同的存储空间,当其中一方发生变化时,另一方并不会发生改变

而引用数据类型的名存储在栈内存,而值存储在堆内存中,当我们使用引用数据类型时实际使用的是栈内存提供的引用地址指向堆内存中的值,

那么当我们引用的值发生变化时,我们本身会发生变化吗?

  1. var a = ['1','2'];
  2. var b = a;
  3. console.log(b);
  4. a.push('3');
  5. console.log(b);
  6. 复制代码

实际上是会的,因为他们指向的同一个地址,这就是浅拷贝

当我们在实际使用时,浅拷贝会给我们带来很多问题,那么深拷贝怎么实现呢?

思路1:递归复制所有属性层级

  1. function deepcopy1(obj) {
  2. let result = Array.isArray(obj)?[]:{};
  3. if(obj && typeof obj === 'object'){
  4. for(let key in obj){
  5. if(obj.hasOwnProperty(key)){
  6. if(obj[key] && typeof obj[key] === 'object'){
  7. result[key] = deepcopy1(obj[key]);
  8. }
  9. else{
  10. result[key] = obj[key]
  11. }
  12. }
  13. }
  14. }
  15. return result;
  16. }
  17. 复制代码
  18. var a = ['1','2',{name:'tina',sex:'female'},'4',{data:[1,2,3,{key:'1'}],msg:'hhhh'}];
  19. var b = deepcopy1(a);
  20. var c = JSON.parse(JSON.stringify(a));
  21. a.push('2');
  22. a[4].data.push('2');
  23. console.log(a);
  24. console.log(b);
  25. 复制代码

问题:

  1. a[10] = a;
  2. 复制代码

当对象中有循环引用时,会报错

思路2:利用js自带的深拷贝方法

  1. var a = ['1','2',{name:'tina',sex:'female'},'4',{data:[1,2,3,{key:'1'}],msg:'hhhh'}];
  2. var c = JSON.parse(JSON.stringify(a));
  3. a.push('2');
  4. a[4].data.push('2');
  5. console.log(a);
  6. console.log(c);
  7. 复制代码

也是可同样的效果

问题: 1.当要深拷贝的对象中有undefined和函数时,拷贝不成功,会出现null

2.当对象中有循环引用时,会报错

思路3:在思路1的方法中检验一下一个对象的字段是否引用了这个对象或这个对象的任意父级

  1. function deepcopy2(obj,parent = null) {
  2. let result = Array.isArray(obj)?[]:{};
  3. let _parent = parent;
  4. while(_parent){
  5. _parent.originalPolicy
  6. if(_parent.originalParent === obj){
  7. return _parent.currentParent;
  8. }
  9. _parent = _parent.parent;
  10. }
  11. if(obj && typeof obj === 'object'){
  12. for(let key in obj){
  13. if(obj.hasOwnProperty(key)){
  14. if(obj[key] && typeof obj[key] === 'object'){
  15. result[key] = deepcopy1(obj[key],{
  16. originaParent:obj,
  17. currentParent:result,
  18. parent:parent
  19. });
  20. }
  21. else{
  22. result[key] = obj[key]
  23. }
  24. }
  25. }
  26. }
  27. return result;
  28. }
  29. 复制代码
  30. var a = ['1','2',{name:'tina',sex:'female'},'4',{data:[1,2,3,{key:'1'}],msg:'hhhh'},undefined,deepcopy1];
  31. var b = deepcopy2(a);
  32. a[10] = a;
  33. a.push('2');
  34. a[4].data.push('2');
  35. console.log(a);
  36. console.log(b);
  37. 复制代码

思路4:深拷贝函数最终版(支持基本数据类型、原型链、RegExp、Date类型)

  1. function deepcopy3(obj, parent = null) {
  2. let result; // 最后的返回结果
  3. let _parent = parent; // 防止循环引用
  4. while(_parent){
  5. if(_parent.originalParent === obj){
  6. return _parent.currentParent;
  7. }
  8. _parent = _parent.parent;
  9. }
  10. if(obj && typeof obj === "object"){ // 返回引用数据类型(null已被判断条件排除))
  11. if(obj instanceof RegExp){ // RegExp类型
  12. result = new RegExp(obj.source, obj.flags)
  13. }else if(obj instanceof Date){ // Date类型
  14. result = new Date(obj.getTime());
  15. }else{
  16. if(obj instanceof Array){ // Array类型
  17. result = []
  18. }else{ // Object类型,继承原型链
  19. let proto = Object.getPrototypeOf(obj);
  20. result = Object.create(proto);
  21. }
  22. for(let key in obj){ // Array类型 与 Object类型 的深拷贝
  23. if(obj.hasOwnProperty(key)){
  24. if(obj[key] && typeof obj[key] === "object"){
  25. result[key] = deepcopy3(obj[key],{
  26. originalParent: obj,
  27. currentParent: result,
  28. parent: parent
  29. });
  30. }else{
  31. result[key] = obj[key];
  32. }
  33. }
  34. }
  35. }
  36. }else{ // 返回基本数据类型与Function类型,因为Function不需要深拷贝
  37. return obj
  38. }
  39. return result;
  40. }
  41. // 调试用
  42. function construct(){
  43. this.a = 1,
  44. this.b = {
  45. x:2,
  46. y:3,
  47. z:[4,5,[6]]
  48. },
  49. this.c = [7,8,[9,10]],
  50. this.d = new Date(),
  51. this.e = /abc/ig,
  52. this.f = function(a,b){
  53. return a+b
  54. },
  55. this.g = null,
  56. this.h = undefined,
  57. this.i = "hello",
  58. this.j = Symbol("foo")
  59. }
  60. construct.prototype.str = "I'm prototype"
  61. var obj1 = new construct()
  62. obj1.k = obj1
  63. obj2 = deepcopy3(obj1)
  64. obj2.b.x = 999
  65. obj2.c[0] = 666
  66. console.log(obj1)
  67. console.log(obj2)
  68. console.log(obj1.str)
  69. console.log(obj2.str)
  70. 复制代码

转载于:https://juejin.im/post/5cac49676fb9a068ad1afc8c

发表评论

表情:
评论列表 (有 0 条评论,377人围观)

还没有评论,来说两句吧...

相关阅读

    相关 拷贝拷贝

    浅拷贝(shallowCopy)只是增加了一个指针指向已存在的内存地址, 深拷贝(deepCopy)是增加了一个指针并且申请了一个新的内存,使这个增加的指针指向这个新的内存,

    相关 拷贝拷贝

    深拷贝和浅拷贝的理解? 深拷贝和浅拷贝是针对复杂数据类型来说的,浅拷贝只拷贝一层,而深拷贝是层层拷贝。 浅拷贝:将原数组和原对象的引用直接拷贝到新数组和新对象,新对象只

    相关 拷贝拷贝

    一、浅拷贝 1、浅拷贝和赋值的区别     赋值:当我们把一个对象赋值给一个新变量时,赋的其实是这个对象在栈中的地址,而不是堆中的数据,也就是两个对象指向的是同一个

    相关 拷贝拷贝

    最近更新时间:2017年11月28日22:44:54 [《我的博客地图》][Link 1]     对于程序员来说,编程语言就像是创作的工具,掌握扎实的语言功底才能创作出优

    相关 拷贝拷贝

    深拷贝和浅拷贝 浅拷贝:对变量进行比较浅层次的拷贝,比如变量的赋值,其实2个变量都指向同一个内存地址。内存地址共享。 深拷贝:对变量进行深层次的拷贝,拷贝了一份数据,2

    相关 拷贝拷贝

    深拷贝和浅拷贝 浅拷贝,只是拷贝基本类型的数据,而引用类型数据,是复制的引用而不是复制的对象。 深拷贝,将原对象所有的数据复制一份到另一个新开辟的空间。 Java

    相关 拷贝拷贝

    浅拷贝 浅拷贝会创建新对象,其内容非原对象本身的引用,而是原对象内第一层对象的引用。 ![在这里插入图片描述][watermark_type_ZmFuZ3poZW5n