一、浅拷贝和深拷贝

浅拷贝:创建一个新对象来接受将要复制的对象值,如果属性值是基本类型则复制一份新的值,如果是引用类型,则保存的是内存的引用值,存在值共享的现象。
深拷贝:创建一个新对象来接受简要复制的对象值,如果属性值是基本类型则复制一份新的值,如果是引用类型,则开辟一个新的内存空间进行保存两个引用数据相互独立,互不影响。

二、浅拷贝的api

1、Object.assign,用于合并对象,属于浅拷贝。

let clonedObj = Object.assign({},origin)

2、拓展运算符展开

let clonedObj = {…origin}
拓展运算符要更简洁

三、深拷贝

1、JSON.Stringify()

缺点:函数、undefined、symbol数据类型经过JSON.Stringify后,键值对会消失

2、基础版:递归赋值

  1. const isComplexDataType = (obj) => (typeof origin === 'object' && origin !== null);
  2. function deepClone(origin){
  3. let newObj;
  4. if(isComplexDataType(origin)){
  5. newObj = Array.isArray(origin) ? [] : {}
  6. for(let key in origin){
  7. if(origin.hasOwnProperty(key)){
  8. if(isComplexDataType(origin[key])){
  9. newObj[key] = Array.isArray(origin[key]) ? [] : {}
  10. newObj[key] = deepClone(origin[key])
  11. }{
  12. newObj[key] = origin[key]
  13. }
  14. }
  15. }
  16. return newObj
  17. }else{
  18. return origin
  19. }
  20. }

缺点:
1、无法正确克隆date、RegExp等类型对象
2、不能克隆不可枚举和synbol类型属性 : 通过Object.create传入owenPropertyDescriptors
3、无法继承原型链: Object.create
4、无法解决循环引用造成的栈溢出问题 通过map来保存拷贝过的值,进一步用weakMap(对key值是弱引用,垃圾回收机制会释放未被引用的key)来自动释放内存

3、解决方案

(1)克隆参数有两个,克隆对象,克隆记录(weakMap,只接受引用值作为箭名,对键值为弱引用,停止引用后,会在垃圾回收机制执行时回收)
(2)判断是否为内置对象实例,regxp,date对象
(3)在克隆记录中查询是否有缓存,有的话,返回缓存值
(4)获取对象原型(解决原型继承问题),属性描述符(解决了getter和setter无法拷贝的问题)
(5)用Object.create创建新对象
(6)遍历新对象自身属性,进行递归拷贝
(7)将此次拷贝记录下来
(8)返回拷贝对象

  1. const isComplexDataType = (obj) => (typeof obj === 'object' && obj !== null);
  2. function deepClone(origin , hash = new WeakMap()){
  3. if(isComplectDataType(obj)){
  4. //判断date、RegExp类型对象
  5. if(instanceof Date){
  6. return new Date(obj)
  7. }
  8. if(instanceof Regxp){
  9. return new Regxp(obj)
  10. }
  11. // 判断hash表中是否已有缓存,避免自身引用导致的循环递归
  12. if(hash.get(obj)) return hash.get(obj)
  13. //获取属性描述符,然后创建新对象
  14. let descriptors = Object.getOwnPropertyDescriptors(obj);
  15. let newObj = Object.create(Object.getPrototypeOf(obj) ,descriptors);//可以创建对象和数组
  16. hash.set(obj, newObj);
  17. for(let key of Reflect.ownKeys(obj)){
  18. newObj[key] = isComplexDataType(origin[key]) ? deepClone(origin[key]) : origin[key]
  19. }
  20. return newObj
  21. }else{
  22. return obj
  23. }
  24. }