首页 > 技术文章 > 浅拷贝和深拷贝

heisetianshi 2022-02-17 10:44 原文

 

当我们进行浅拷贝时,拷贝基本数据类型和引用数据类型的情况是不一样的。

为什么呢?因为两种情况下内存发生的变化不一样。

1、拷贝基本数据类型举例:

1     var video = 100;
2     var copy = video;
3     copy = 10000;
4     console.log(video);     // 100
5     console.log(copy);      // 10000

我们发现修改copy的值,不会影响video。

内存中发生什么呢?video相当于一个标识符,会为其分配一个内存地址,存储的值为100。拷贝给copy,vedio和copy都指向一个内存地址。然后给copy赋新值,会开辟新的内存地址。存在栈内存中。

 

 2、拷贝引用数据类型举例:

1     var video = {
2           like: 100
3     };
4     var copy = video;
5     copy.like = 10000;
6     console.log(video);
7     console.log(copy);

结果发现修改copy,会影响video。

 

 此时内存发生什么呢?video相当于一个标识符,会为其分配一个栈内存地址,这个内存地址提供一个新的引用地址指向堆内存中的值。

 我们可以通过什么方法进行浅拷贝?(注意是对象)

1、惯用的方法,即赋值法 2、通过Object.assign() ,从代码上可以看出前提是对象(当然了,基本数据类型虽然也不会报错)3、for...in(只循环第一层)

这里只提供下for...in的方法代码

 1 function simpleCopy(obj1) {
 2       var obj2 = Array.isArray(obj1) ? [] : {};
 3       for (let i in obj1) {
 4         obj2[i] = obj1[i];
 5       }
 6       return obj2;
 7     }
 8     var obj1 = {
 9       a: 1,
10       b: 2,
11       c: {
12         d: 3
13       }
14     };
15     var obj2 = simpleCopy(obj1);
16     obj2.a = 3;
17     obj2.c.d = 4;
18     console.log(obj1);
19     console.log(obj2);

 

深拷贝方法:

1、使用JSON.parse(JSON.stringify())

1     var video = {
2       like: 100
3     };
4     var copy = JSON.parse(JSON.stringify(video));
5     copy.like = 10000;
6     console.log(video);
7     console.log(copy);

缺点:它是不可以拷贝 undefined , function, RegExp 等等类型的

2、递归拷贝,封装一个函数(推荐)

 1  let obj1 = {
 2         a: {
 3             c: /a/,
 4             d: undefined,
 5             b: null
 6         },
 7         b: function () {
 8             console.log(this.a)
 9         },
10         c: [
11             {
12                 a: 'c',
13                 b: /b/,
14                 c: undefined
15             },
16             'a',
17             3
18         ]
19     }
20     let obj2 = deepClone(obj1);
21     console.log(obj1);
22     console.log(obj2);

封装的深拷贝函数如下:

 1 // 定义一个深拷贝函数  接收目标target参数
 2     function deepClone(target) {
 3       // 定义一个变量
 4       let result;
 5       // 如果当前需要深拷贝的是一个对象的话
 6       if (typeof target === "object") {
 7         // 如果是一个数组的话
 8         if (Array.isArray(target)) {
 9           result = []; // 将result赋值为一个数组,并且执行遍历
10           for (let i in target) {
11             // 递归克隆数组中的每一项
12             result.push(deepClone(target[i]));
13           }
14           // 判断如果当前的值是null的话;直接赋值为null
15         } else if (target === null) {
16           result = null;
17           // 判断如果当前的值是一个RegExp对象的话,直接赋值
18         } else if (target.constructor === RegExp) {
19           result = target;
20         } else {
21           // 否则是普通对象,直接for in循环,递归赋值对象的所有值
22           result = {};
23           for (let i in target) {
24             result[i] = deepClone(target[i]);
25           }
26         }
27         // 如果不是对象的话,就是基本数据类型,那么直接赋值
28       } else {
29         result = target;
30       }
31       // 返回最终结果
32       return result;
33     }

 

推荐阅读