实现深拷贝的多种方式

实现深拷贝的多种方式

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

①for循环拷贝

// 只复制第一层的浅拷贝

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

②Object.assign()实现一层深拷贝

1 var obj1 = { 2 a: 1, 3 b: 2, 4 c: 3 5} 6var obj2 = Object.assign({}, obj1); 7obj2.b = 5; 8console.log(obj1.b); // 2 9console.log(obj2.b); // 5 10 var obj1 = { 11 a: 1, 12 b: 2, 13 c: ['a','b','c'] 14} 15var obj2 = Object.assign({}, obj1); 16obj2.c[1] = 5; 17console.log(obj1.c); // ["a", 5, "c"] 18console.log(obj2.c); // ["a", 5, "c"] 19 20

③slice实现

1// 对只有一级属性值的数组对象使用slice 2var a = [1,2,3,4]; 3var b = a.slice(); 4b[0] = 2; 5alert(a); // 1,2,3,4 6alert(b); // 2,2,3,4 7// 对有多层属性的数组对象使用slice 8var a = [1,[1,2],3,4]; 9var b = a.slice(); 10b[1][0] = 2; 11alert(a); // 1,2,2,3,4 12alert(b); // 1,2,2,3,4 13 14

④通过Object.create()实现

1function deepCopy(obj) { 2 var copy = Object.create(Object.getPrototypeOf(obj)); 3 var propNames = Object.getOwnPropertyNames(obj); 4 5 propNames.forEach(function(name) { 6 var desc = Object.getOwnPropertyDescriptor(obj, name); 7 Object.defineProperty(copy, name, desc); 8 }); 9 10 return copy; 11} 12 13var obj1 = { a: 1, b: {bc: 50, dc: 100, be: {bea: 1}} }; 14var obj2 = deepCopy(obj1); 15obj2.a = 20; 16obj2.b.bc = 60; 17console.log(obj1.a)//1 18console.log(obj2.a)//20 19console.log(obj1.b.bc)//60 20console.log(obj2.b.bc)//60 21 22

2.粗暴深拷贝(抛弃对象的constructor)

使用jsON.stringify和jsON.parse实现深拷贝:JSON.stringify把对象转成字符串,再用JSON.parse把字符串转成新的对象;

1function deepCopy(obj1){ 2 let _obj = JSON.stringify(obj1); 3 let obj2 = JSON.parse(_obj); 4 return obj2; 5} 6var a = [1, [1, 2], 3, 4]; 7var b = deepCopy(a); 8b[1][0] = 2; 9alert(a); // 1,1,2,3,4 10alert(b); // 2,2,2,3,4 11 12

缺陷:它会抛弃对象的constructor,深拷贝之后,不管这个对象原来的构造函数是什么,在深拷贝之后都会变成Object;这种方法能正确处理的对象只有 Number, String, Boolean, Array, 扁平对象,也就是说,只有可以转成JSON格式的对象才可以这样用,像function没办法转成JSON;

1let obj1 = { 2 fun:function(){ 3 alert(123); 4 } 5} 6let obj2 = JSON.parse(JSON.stringify(obj1)); 7console.log(typeof obj1.fun); // function 8console.log(typeof obj2.fun); // undefined 9 10

3.复杂深拷贝(相对完美)

递归拷贝实现深拷贝,解决循环引用问题

1/** 2 * 判断是否是基本数据类型 3 * @param value 4 */ 5function isPrimitive(value){ 6 return (typeof value === 'string' || 7 typeof value === 'number' || 8 typeof value === 'symbol' || 9 typeof value === 'boolean') 10} 11 12/** 13 * 判断是否是一个js对象 14 * @param value 15 */ 16function isObject(value){ 17 return Object.prototype.toString.call(value) === "[object Object]" 18} 19 20/** 21 * 深拷贝一个值 22 * @param value 23 */ 24function cloneDeep(value){ 25 26 // 记录被拷贝的值,避免循环引用的出现 27 let memo = {}; 28 29 function baseClone(value){ 30 let res; 31 // 如果是基本数据类型,则直接返回 32 if(isPrimitive(value)){ 33 return value; 34 // 如果是引用数据类型,我们浅拷贝一个新值来代替原来的值 35 }else if(Array.isArray(value)){ 36 res = [...value]; 37 }else if(isObject(value)){ 38 res = {...value}; 39 } 40 41 // 检测我们浅拷贝的这个对象的属性值有没有是引用数据类型。如果是,则递归拷贝 42 Reflect.ownKeys(res).forEach(key=>{ 43 if(typeof res[key] === "object" && res[key]!== null){ 44 //此处我们用memo来记录已经被拷贝过的引用地址。以此来解决循环引用的问题 45 if(memo[res[key]]){ 46 res[key] = memo[res[key]]; 47 }else{ 48 memo[res[key]] = res[key]; 49 res[key] = baseClone(res[key]) 50 } 51 } 52 }) 53 return res; 54 } 55 56 return baseClone(value) 57} 58 59

4.ES插件lodash

1import lodash from 'lodash' 2 3var objects = [1,{ 'a': 1 }, { 'b': 2 }]; 4var deep = lodash.cloneDeep(objects); 5deep[0] = 2; 6deep[1].a = 2; 7console.log(objects[0]);//1 8console.log(deep[0]);//2 9console.log(objects[1].a);//1 10console.log(objects[1].a);//2 11 12
点赞
收藏

评论区

加载中...

相关推荐

ES6的解构赋值是深拷贝or浅拷贝?

面试时候有面试官问到ES6的解构赋值是深拷贝还是浅拷贝?,这里做一个总结.ES6的解构赋值,大家应该都清楚,就是可以快速取出数组或者对象中的值;我们先来看一个使用案例:更多的解构赋值知识可以查看:https://es6.ruanyifeng.com/docs/destructuring那么,ES6的解构赋值到底是深拷贝还是浅拷贝呢?我们先来看一下深拷贝和浅

java 复制Map对象(深拷贝与浅拷贝)

java复制Map对象(深拷贝与浅拷贝)CreationTime2018年6月4日10点00分Author:Marydon1.深拷贝与浅拷贝  浅拷贝:只复制对象的引用,两个引用仍然指向同一个对象

仔细看看,会有收获。js深浅拷贝

好好理解深浅拷贝和赋值(针对引用类型)赋值:两个对象指向同一内存地址。结果,无论是修改基本类型还是引用类型,两个对象的值都会改变。浅拷贝:两个对象指向不同的内存地址,但是他们中的引用类型数据指向同一内存地址。结果,修改引用类型,两个对象的值都会改变;修改基本类型,互不影响。深拷贝:两个对象指向不同的内存地址,他们中的引用类型也指向不同的内存地址。结果,均互不

也谈JavaScript浅拷贝和深拷贝

网上关于这个话题,讨论有很多了,根据各路情况我自己整理了一下,最后还是能接近完美的实现深拷贝,欢迎大家讨论。javascript中的对象是引用类型,在复制对象的时候就要考虑是用浅拷贝还是用深拷贝。直接赋值对象是引用类型,如果直接赋值给另外一个对象,那么只是赋值一个引用,实际上两个变量指向的同一个数据对象,如果其中一个对象的属性变更,那么另外一个也会变更。示

Java对象拷贝原理剖析及最佳实践

作者:宁海翔1前言对象拷贝,是我们在开发过程中,绕不开的过程,既存在于Po、Dto、Do、Vo各个表现层数据的转换,也存在于系统交互如序列化、反序列化。Java对象拷贝分为深拷贝和浅拷贝,目前常用的属性拷贝工具,包括Apache的

带你了解JS对象的浅拷贝和深拷贝

以下主要介绍了正常情况下的拷贝、浅拷贝、深拷贝三种方式的区别。正常拷贝:复制一个对象,它们的内存地址是相同的浅拷贝:拷贝对象的第一层属性深拷贝:拷贝对象多层的属性正常拷贝假设我们要复制一个对象,如果不对其进行深拷贝,那么改变其中一个对象后,另外一个对象也会

实现深拷贝的多种方式 - HelloWorld