# 深浅拷贝

# 浅拷贝

只是复制栈的内存地址,如果另一个对象改变堆的值,本身会发生改变

  1. 引用复制
function shallowCopy(target){
  const res = {}
  for(let key in target){
    res[key] = target[key]
  }
  return res
}
  1. Object.assign
var x = {
  a: 1,
  b: { f: { g: 1 } },
  c: [ 1, 2, 3 ]
};
var y = Object.assign({}, x);
console.log(y.b.f === x.b.f);     // true

  1. 利用扩展运算符

# 深拷贝

完全拷贝,互不影响

  1. 递归实现
function deepclone(target = {}){
  if(target == null || typeof obj !== object){
    return target
  }
  let res
  if(target instanceof Array){
    res =[]
  }else{
    res = {}
  }
  for(let key in target){
    // 保证不是原型对象上的属性
    if(target.hasOwnPropetry(key)){
      res[key] = deepclone(target[key])
    }
  }
return res
}

完整版本

// Map 强引用,需要手动清除属性才能释放内存。
// WeakMap 弱引用,随时可能被垃圾回收,使内存及时释放,是解决循环引用的不二之选。
function cloneDeep(obj, map = new WeakMap()) {
  if (!(obj instanceof Object)) return obj; // 基本数据
  if (obj instanceof Date) return new Date(obj);
  if (obj instanceof RegExp) return new RegExp(obj.source, obj.flags);
  
  if (map.get(obj)) return map.get(obj); // 解决循环引用
  
  if (obj instanceof Function) { // 解决函数
    return function () {
      return obj.apply(this, [...arguments]);
    };
  }
  
  const res = new obj.constructor(); // 下面是数组/普通对象/Set/Map 的处理
  
  obj instanceof Object && map.set(obj, res);
  if (obj instanceof Map) {
    obj.forEach((item, index) => {
      res.set(cloneDeep(index, map), cloneDeep(item, map));
    });
  }
  if (obj instanceof Set) {
    obj.forEach((item) => {
      res.add(cloneDeep(item, map));
    });
  }
  Object.keys(obj).forEach((key) => {
    if (obj[key] instanceof Object) {
      res[key] = cloneDeep(obj[key], map);
    } else {
      res[key] = obj[key];
    }
  });
  return res;
}

const map = new Map();
map.set({ a: 1 }, "1");
const source = {
  name: "Jack",
  meta: {
    age: 12,
    birth: new Date("1997-10-10"),
    ary: [1, 2, { a: 1 }],
    say() {
      console.log("Hello");
    },
    map
  },
};
source.source = source;
const newObj = cloneDeep(source);
console.log(newObj.meta.ary[2] === source.meta.ary[2]); // false
console.log(newObj.meta.birth === source.meta.birth); // false
console.log(newObj);

  1. JSON.parse(JSON.stringify(target))

弊端

  1. obj里有 date 对象无法被序列化和反序列化,而是转为date字符串
  2. obj里有 RegExp 对象,Error 对象序列化结果是空对象
  3. obj里有 function,undefined会被丢失
  4. obj里有 NaN,Infinity,-Infinity 序列化结果会变成null
  1. loadash
Last update: 3/18/2021, 11:53:59 PM