js实现深拷贝和浅拷贝

1,深拷贝与浅拷贝的区别

深拷贝:主要是将另一个对象的属性值拷贝过来之后,另一个对象的属性值并不受到影响,它自己在堆中开辟了自己的内存区域,不受外界干扰。
浅拷贝:主要拷贝的是对象的引用值,当改变对象的值,另一个对象的值也会发生变化。

2,常见的实现对象的深拷贝方法:

1)JSON.parse( JSON.stringify() ) 序列化和反序列

 1 var obj = {
 2     a: '123',
 3     b: 234,
 4     c: true,
 5     d: null,
 6     e: function() {console.log('test')},
 7     h: new Set([4,3,null]),
 8     i:Symbol('fsd'),
 9     k: new Map([ ["name", "test"],  ["title", "Author"]  ])
10 }
11 console.log(JSON.stringify(obj)); 
12 // {"a":"123","b":234,"c":true,"d":null,"h":{},"k":{}}

可以看到data这个对象的属性里基本上包含了所有的数据类型,但通过JSON字符串化后,返回的值却有缺失,原因是JSON在执行字符串化的这个过程时,会先进行一个JSON格式化,获得安全的JSON值,因此如果是非安全的JSON值,就会被丢弃掉。其中undefined、function、symbol这三种类型的值就是非安全的(包括该对象的属性循环赋值该对象),所以格式化后,就被过滤掉了,而set、map这种数据格式的对象,也并没有被正确处理,而是处理成了一个空对象。

2)Object.assign(target, source1, source2)

es6新增的方法,可用于对象合并,将源对象的所有可枚举属性,复制到目标对象上。

 1 var obj = {
 2     a: '123',
 3     b: 234,
 4     c: true,
 5     d: null,
 6     e: function() {console.log('test')},
 7     h: new Set([4,3,null]),
 8     i:Symbol('fsd'),
 9     k: new Map([ ["name", "test"],  ["title", "Author"]  ])
10 }
11 var newData = Object.assign({},obj)
12 console.log(newData)

注意:当对象中只有一级属性,没有二级属性的时候,此方法为深拷贝,但是对象中有对象的时候,此方法,在二级属性以后就是浅拷贝

3)使用递归方法

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

4)lodash函数库实现深拷贝

1 let clone = cloneDeep(obj)

3,常见的实现数组的深拷贝方法:

1)for循环实现

1 var arr = [1,2,3,4,5]
2 var arr2 = copyArr(arr)
3 function copyArr(arr) {
4     let res = []
5     for (let i = 0; i < arr.length; i++) {
6      res.push(arr[i])
7     }
8     return res

2)slice方法  原理:将原数组中抽离部分出来形成一个新数组。只要设置为抽离全部,即可完成数组的深拷贝

1 var arr = [1,2,3,4,5]
2 var arr2 = arr.slice(0)
3 arr[2] = 5
4 console.log(arr)
5 console.log(arr2)

注意:

①没有参数的时候,是拷贝数组
②一个参数的时候,拷贝从起始位置到数组末尾的元素
③两个参数的时候,拷贝从起始位置到 结束位置的元素(不包含结束位置的元素,含头不含尾)
一维数组元素是深拷贝,数组元素二维以上是值的引用

3)concat方法  原理:用于连接多个数组组成一个新的数组的方法。那么,只要连接它自己,即可完成数组的深拷贝

1 var arr = [1,2,3,4,5]
2 var arr2 = arr.concat()
3 arr[2] = 5
4 console.log(arr)
5 console.log(arr2)

注意只有在数组元素是一维的时候,是深拷贝,一维以上是对值的引用

4)ES6扩展运算符实现

1 var arr = [1,2,3,4,5]
2 var [ ...arr2 ] = arr
3 arr[2] = 5
4 console.log(arr)
5 console.log(arr2)

 

posted @ 2022-12-19 16:40  程序员肉包子  阅读(390)  评论(0编辑  收藏  举报