浅拷贝与深拷贝
在JS中,复制一个对象有浅拷贝和深拷贝之说。那么浅拷贝和深拷贝有哪些区别呢?在哪些方面会体现呢?
#
待复制对象的属性JS中的有6种数据类型:字符串,数字,布尔,null,undefined,object。如果一个对象的属性是前5种,那么就没有浅拷贝和深拷贝之分。但是如果待复制的对象中某个属性是对象的话,就会出现浅拷贝和深拷贝的区别了。
#
浅拷贝和深拷贝区别对象,由引用和对象的内容组成,引用是在内存中的栈内,真正的对象的内容,在内存中是在堆内。
而对于对象的复制,如果只是复制了引用,那这就是浅拷贝。假如源对象中有属性为对象的话,源对象A和复制后的对象B,使用同一个引用指向相同的对象C。通过A改变C的内容,B中C的内容也会被修改。反之亦然。
如果是深拷贝的话,源对象的属性中有对象的话,目标对象中会生成一个新的对象,而不会共用同一个引用。目标对象会生成一个新的对象,引用和对象的内容,栈和堆中都会分别生成一个新的内容。
#
浅拷贝的方法- 使用Object.assign(),会通过浅拷贝生成一个新的对象。
var obj = Object.assign({}, src);
function shallowCopy(src) { var obj = {}; for(let key in src) { obj[key] = src[key]; } return obj;}
#
深拷贝的方法- 将对象转换为json字符串,再反解析回来。但是对于对象中的function对象、正则表达式对象无法复制。而且会丢失对象的原型链,新生成的对象的constructor都会变为object。
var src = { name: "lrq", age: 18, hobbies: { sing: "songs", play: "football" }}var obj = JSON.parse(JSON.stringify(src))
- 递归操作,可以将源对象中的对象和数组进行复制
function deepClone(src) { var obj = src.constructor===Array?[]:{}; for(let key in src) { if(src.hasOwnProperty(key)) { if(src[key] && typeof src[key]=='object') { obj[key] = src[key].constructor===Array?[]:{}; obj[key] = deepClone(src[key]); } else { obj[key] = src[key]; } } } return obj;}
#
重大更新找到一种新的便捷方法来应对obj是数组或者对象,同时也对正则和日期对象有了处理。
如下:
function deepClone(obj, map=new WeakMap()) { if(obj===null) return null; if(obj instanceof RegExp) return new RegExp(obj); //是正则对象则直接new一个正则对象 if(obj instanceof Date) return new Date(obj); //是Date对象则直接new一个Date对象 if(typeof obj !== 'object') return obj; //基本类型值则直接返回 if(map.has(obj)) return map.get(obj); //如果map里面有,则直接返回,防止自身引用无限调用
let ret = new obj.constructor(); //管你是数组还是对象,直接上构造函数 map.set(obj, ret); //放入map中 for(let key in obj) { ret[key] = deepClone(obj[key], map); //对每个属性都进行深拷贝 } return ret;}