JS 深拷贝 VS 浅拷贝
复习到深浅拷贝问题,简单Mark一下实现方法。
## 写在前面
首先我们得清楚基本概念。拷贝(Copy)即复制。
浅拷贝:创建一个新对象,保存原始对象属性值精准拷贝。如果属性是基本类型,拷贝的是基本类型的值,如果属性是引用类型,拷贝的是内存地址,并不会占用新的内存,这种情况下如果其中一个对象改变了这个地址,会影响到另一个对象。浅拷贝只复制指向某个对象的指针,而不复制对象本身。**新旧对象共享同一块内存**。
深拷贝:将一个对象从内存中完整的拷贝一份出来,从堆内存中开辟一个新的区域存放新对象,增加了内存,且修改新对象不会影响原对象。**新对象与原对象不共享内存**。
## 赋值和深/浅拷贝的区别(针对引用类型)
赋值:把一个对象赋值给一个新的变量时,赋的其实是该对象的在栈中的地址,而不是堆中的数据。
浅拷贝:重新在堆中创建内存,拷贝前后对象的基本数据类型互不影响,但拷贝前后对象的引用类型因共享同一块内存,会相互影响。
深拷贝:从堆内存中开辟一个新的区域存放新对象,对对象中的子对象进行递归拷贝,前后的两个对象互不影响。
## 浅拷贝的实现方案
### 0x01 Object.assign()
把任意多个源对象自身的可枚举属性拷贝给目标对象,然后返回目标对象。
let obj2 = Object.assign({}, obj1)
### 0x02 函数库lodash的_.clone方法
var _ = require('lodash'); var obj2 = _.clone(obj1);
### 0x03 展开运算符
同object.assign()功能相同
let obj2 = {...obj1}
### 0x04 Array.prototype.concat()
let arr2 = arr1.concat()
### 0x05 Array.prototype.slice()
let arr2 = arr1.slice()
## 深拷贝的实现方案
### 0x01 JSON.parse()和JSON.stringify()
let arr2 = JSON.parse(JSON.stringify(arr1));
缺点是不能处理函数和正则
### 0x02 函数库lodash的_.cloneDeep方法
var _ = require('lodash'); var obj2 = _.cloneDeep(obj1);
### 0x03 jQuery.extend()方法
$.extend(deepCopy,target,obj1,[objN]) // 第一个参数为true就是深拷贝
### 0x04 手写递归实现
解决循环引用的问题
function deepClone(obj, hash=new WeakMap()) { if(obj == null) return obj; // 不操作 if(obj instanceof Date) return new Date(obj); if(obj instanceof RegExp) return new RegExp(obj); // 普通值/函数不需要深拷贝 if(typeof obj !== "object") return obj; // 是对象的话要进行深拷贝 if(hash.get(obj)) return hash.get(obj); let cloneObj = new obj.constructor(); // 找到的是所属类原型上的constructor,而原型上的constructor指向的是当前类本身 hash.set(obj. cloneObj); for(let key in obj) { if(obj.hasOwnProperty(key)) { cloneObj[key] = deepClone(obj[key], hash) } } return cloneObj; }