带你搞懂js的深拷贝

39 篇文章 1 订阅

带你搞懂js的深拷贝

 更新时间:2021年11月15日 16:01:01   作者:浪漫主义码农  
这篇文章主要为大家介绍了js的深拷贝,具有一定的参考价值,感兴趣的小伙伴们可以参考一下,希望能够给你带来帮助

js深拷贝

在讲正题之前我们要先了解数据存储的方式

数据存储方式

在讲之前我们要先知道值类型和引用类型的存储方式。

在JavaScript数据类型中有两种数据类型。

值类型:字符串(String)、数字 (Number)、布尔 (Boolean)、空(Null)、未定义(Undefined)、Symbol

存放在栈内存中的简单数据段,数据大小确定,内存空间大小可以分配。

引用数据类型:对象 (Object) 、数组 (Array) 、函数 (Function) 。

存放在堆内存中的对象,在栈内存中存的是一个指针,这个指针指向堆内存一个位置。再从堆内存中取得所需的数据。

存储如下图:

什么是浅/深拷贝

讲完存储的方式,我们来讲讲浅拷贝和深拷贝

拷贝也就是我们常常讲的copy,ctrl+c,ctrl+v,那么我们来看看例子

当我们对分别值类型和引用类型进行赋值。

1
2
3
4
5
6
7
8
9
var a = 5
var b = a
b += 5
console.log('a=' + a,'b=' + b)
var arr=[1,2,3]
var brr=arr
brr.push(10)
console.log("arr为",arr)
console.log("brr为",brr)

现象:我们发现值类型并没有互相受到影响,然而数组(引用类型)brr数组添加元素的时候改变了arr数组。

解释分析:浅拷贝只会发生在引用类型身上,对于引用类型如果之进行简单的赋值,只会赋值指向堆内存的指针,这种称为浅拷贝。而深拷贝就是完全拷贝一个引用类型,为不是地址指针。

浅拷贝看下面这张原理图:

常用深拷贝实现

那么我们在赋值引用类型的时候肯定不能出现浅拷贝的现象,对原数据产生影响了。那么就要进行深拷贝

1.通过JSON.stringify和JSON.parse

可以深拷贝的数组和对象,但是不能拷贝函数,可以进行对象或者数组的嵌套拷贝。

缺点:无法实现对对象中方法的深拷贝

使用

1
var brr=JSON.parse(JSON.stringify(arr))

例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
var arr = {
       name: '浪漫主义码农',
       age: 20,
       adress: ['jiangxi', 'changsha'],
       friends: {
           friend1: '张三',
           friend2: '李四'
       },
       function(){
           console.log("我是浪漫主义的对象")
       }
   }
   var brr=JSON.parse(JSON.stringify(arr))
   brr.name='法外狂徒张三'
   brr.adress[0]='长沙'
   console.log("arr为", arr)
   console.log("brr为", brr)

2.扩展运算符

利用了对象的结构赋值特性方法。

缺点:无对对象里面嵌套的对象进行深拷贝,相当于只是对一层引用对象进行深拷贝

使用:

1
var brr={...arr}

例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
var arr = {
       name: '浪漫主义码农',
       age: 20,
       adress: ['jiangxi', 'changsha'],
       friends: {
           friend1: '张三',
           friend2: '李四'
       },
       function(){
           console.log("我是浪漫主义的对象")
       }
   }
   var brr={...arr}
   brr.name='法外狂徒张三'
   brr.adress[0]='长沙'
   console.log("arr为", arr)
   console.log("brr为", brr)

3.手写递归深拷贝函数

完美解决

函数:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
//使用递归实现深拷贝
   function deepClone(obj) {
       //判断拷贝的obj是对象还是数组
       var objClone = Array.isArray(obj) ? [] : {};
       if (obj && typeof obj === "object") { //obj不能为空,并且是对象或者是数组 因为null也是object
           for (key in obj) {
               if (obj.hasOwnProperty(key)) {
                   if (obj[key] && typeof obj[key] === "object") { //obj里面属性值不为空并且还是对象,进行深度拷贝
                       objClone[key] = deepClone(obj[key]); //递归进行深度的拷贝
                   } else {
                       objClone[key] = obj[key]; //直接拷贝
                   }
               }
           }
       }
       return objClone;
   }

例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
     var arr = {
        name: '浪漫主义码农',
        age: 20,
        adress: ['jiangxi', 'changsha'],
        friends: {
            friend1: '张三',
            friend2: '李四'
        },
        fun: function(){
            console.log("我是" + this.name + "的对象")
        }
    }
    var brr = deepClone(arr)
    brr.name = '法外狂徒张三'
    brr.adress[0] = '长沙'
    console.log("arr为", arr)
    arr.fun()
    console.log("brr为", brr)
    brr.fun()
    //使用递归实现深拷贝
    function deepClone(obj) {
        //判断拷贝的obj是对象还是数组
        var objClone = Array.isArray(obj) ? [] : {};
        if (obj && typeof obj === "object") { //obj不能为空,并且是对象或者是数组 因为null也是object
            for (key in obj) {
                if (obj.hasOwnProperty(key)) {
                    if (obj[key] && typeof obj[key] === "object") { //obj里面属性值不为空并且还是对象,进行深度拷贝
                        objClone[key] = deepClone(obj[key]); //递归进行深度的拷贝
                    } else {
                        objClone[key] = obj[key]; //直接拷贝
                    }
                }
            }
        }
        return objClone;
    }

总结

本篇文章就到这里了,希望能够给你带来帮助,也希望您能够多多关注脚本之家的更多内容!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值