Skip to main content

浅拷贝与深拷贝

在JS中,复制一个对象有浅拷贝和深拷贝之说。那么浅拷贝和深拷贝有哪些区别呢?在哪些方面会体现呢?


待复制对象的属性#

JS中的有6种数据类型:字符串,数字,布尔,null,undefined,object。如果一个对象的属性是前5种,那么就没有浅拷贝和深拷贝之分。但是如果待复制的对象中某个属性是对象的话,就会出现浅拷贝和深拷贝的区别了。


浅拷贝和深拷贝区别#

对象,由引用和对象的内容组成,引用是在内存中的栈内,真正的对象的内容,在内存中是在堆内。

而对于对象的复制,如果只是复制了引用,那这就是浅拷贝。假如源对象中有属性为对象的话,源对象A和复制后的对象B,使用同一个引用指向相同的对象C。通过A改变C的内容,B中C的内容也会被修改。反之亦然。

如果是深拷贝的话,源对象的属性中有对象的话,目标对象中会生成一个新的对象,而不会共用同一个引用。目标对象会生成一个新的对象,引用和对象的内容,栈和堆中都会分别生成一个新的内容。


浅拷贝的方法#

  1. 使用Object.assign(),会通过浅拷贝生成一个新的对象。
var obj = Object.assign({}, src);
function shallowCopy(src) {    var obj = {};    for(let key in src) {        obj[key] = src[key];    }    return obj;}

深拷贝的方法#

  1. 将对象转换为json字符串,再反解析回来。但是对于对象中的function对象、正则表达式对象无法复制。而且会丢失对象的原型链,新生成的对象的constructor都会变为object。
var src = {    name: "lrq",    age: 18,    hobbies: {        sing: "songs",        play: "football"    }}var obj = JSON.parse(JSON.stringify(src))
  1. 递归操作,可以将源对象中的对象和数组进行复制
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;}