一.定义:

1.浅拷贝

创建一个新对象,这个对象有着原始对象属性值的一份精确拷贝。如果属性是基本类型,拷贝的就是基本类型的值,如果属性是引用类型,拷贝的就是内存地址 ,所以如果其中一个对象改变了这个地址,就会影响到另一个对象。

2.深拷贝

将一个对象从内存中完整的拷贝一份出来,从堆内存中开辟一个新的区域存放新对象,且修改新对象不会影响原对象

浅拷贝存在问题

let a = {

  a:'a'

}

let b = a;

b.a = 'b';

console.log(a.a);//b

深拷贝方法

一.乞丐版:JSON.stringify()

缺点:(从数据类型分析  时间对象、正则对象 Error对象 、function Undefined 、NaN 正负无穷 、循环引用 和 丢失constructor)

1.如果拷贝对象是个时间对象,JSON.stringify()方法会将时间对象转换为时间字符串,JSON.parse()反转后也只是将时间转为字符串形式而不是对象。

2.new RegExp()和new Error()对象 会被 JSON.stringify()转化为空对象字符串:'{}'

3.函数和undefined 会被JSON.stringify()转化为undefined JSON.parse()反转时报错

4.NaN、Infinity和-Infinity会被转换为null

5.JSON.stringify()只能序列化对象的可枚举的自有属性 如果拷贝的对象是 构造函数new 生成的  会丢失对象的constructor属性

6.如果对象中存在循环引用的情况也无法正确实现深拷贝;

二.基础版(没有考虑数组等情况)

function clone(obj){
  if(typeof obj !== 'object') return obj;
  let newObj = {};
  for(let k in obj){
    newObj[k] = clone(obj[k]);
  }
  return newObj;
}

三.考虑数组情况

function clone(obj){
  if(typeof obj !== 'object') return obj;
  let newObj = Array.isArray(obj) : [] : {};
  for(let k in obj){
    newObj[k] = clone(obj[k]);
  }
  return newObj;
}

四.考虑循环引用情况

function clone(obj,map=new Map()){
  if(typeof obj !== 'object') return obj;
  let newObj = Array.isArray(obj)?[]:{};
  if(map.get(obj)){
    return map.get(obj);
  }
  map.set(obj,newObj);
  for(let k in obj){
    newObj[k] = clone(obj[k],map);
  }
  return newObj;
}

五.完整版

//数据类型
const mapTag = '[object Map]';
const setTag = '[object Set]';
const arrayTag = '[object Array]';
const objectTag = '[object Object]';

const boolTag = '[object Boolean]';
const dateTag = '[object Date]';
const errorTag = '[object Error]';
const numberTag = '[object Number]';
const regexpTag = '[object RegExp]';
const stringTag = '[object String]';
const symbolTag = '[object Symbol]';

//判断数据是否为对象
function isObject(data){
const type = typeof data;
return data!==null && (type === 'object' || type === 'function');
}

//初始化一个相应数据类型的新对象
function getInit(data){
const Fn = data.constructor;
return new Fn();
}

//判断数据类型
function getType(data){
return Object.prototype.toString.call(data);
}

//抽象foreach方法
function foreach(arr,fn){
let index = 0;
while(index<arr.length){
fn(arr[index],index);
index++;
}
return arr;
}

//clone方法
function clone(target,map=new WeakMap()){
if(!isObject(target)) return target;

let type = getType(target);
let newTarget = getInit(type);

if(map.get(target)){
return map.get(target);
}
map.set(target,newTarget);

//克隆set
if(type == setTag){
target.foreach(v=>{
newTarget.add(clone(v).map);
})
return newTarget;
}

//克隆map
if(type == mapTag){
target.foreach((v,k)=>{
newTarget.set(k,clone(v,map));
})
return newTarget;
}

//克隆数组或对象
if(type == mapTag){
target.foreach((v,k)=>{
newTarget.set(k,clone(v,map));
})
return newTarget;
}




if(isArray){
foreach(target,function(val,key){
newTarget[key] = val;
})
}else{
foreach(keys,function(val,key){
newTarget[val] = clone(target[val],map);
})
}
return newTarget;
}

posted on 2021-05-31 15:38  皮杰克  阅读(87)  评论(0编辑  收藏  举报