# 深拷贝和浅拷贝

浅拷贝是只拷贝对象的第一层的属性和值,如果拷贝的属性的值是一个对象,则拷贝的是对象的引用地址。

function shadowCopy(obj) {
  var newObj = {};
  for ([key, value] of Object.entries(obj)) {
    newObj[key] = value;
  }
  return newObj;
}
var obj = { a: 'something', b: { c: 1 } };
const newObj = shadowCopy(obj);
newObj.a = 'hello world';
newObj.b.c = 2;
console.log(newObj, obj);
//result
//{ a: 'hello world', b: { c: 2 } } { a: 'something', b: { c: 2 } }

深拷贝的意思是拷贝所有属性和值,深拷贝前后两个对象是独立的,互相不影响。

function deepCopy(obj, map = new WeakMap()) {
  //是否为基本类型数据
  if (isObject(obj)) {
    //判断是否为循环引用
    if (map.get(obj)) {
      return map.get(obj);
    }
    let type = [RegExp, Date, Set, Map, WeakMap, WeakSet];
    if (type.includes(obj.constructor)) {
      return new obj.constructor(obj);
    }
    let allDes = Object.getOwnPropertyDescriptors(obj);
    let cloneObj = Object.create(Object.getPrototypeOf(obj), allDes);
    for (const prop of Reflect.ownKeys(obj)) {
      cloneObj[prop] = isObject(obj[prop]) && typeof obj[prop] !== 'function' ? deepCopy(obj[prop], map) : obj[prop];
    }
    return cloneObj;
  } else {
    return obj;
  }
}

function isObject(obj) {
  return obj != null && (typeof obj === 'object' || typeof obj === 'function');
}

let obj = {
  fun: function() {},
  syb: Symbol('foo'),
  a: undefined,
  b: NaN,
  c: Infinity,
  reg: /^abc$/,
  date: new Date(),
  set: new Set([1, 2, 3, 4, 4]),
  map: new Map([
    ['name', '张三'],
    ['title', 'Author'],
  ]),
  text: 'aaa',
  value: {
    a: {
      b: 2,
    },
  },
};
let cloneObj = deepCopy(obj);

obj.value.a.b = 3;

console.log('cloneObj', cloneObj);
console.log('obj', obj);

打印结果:

cloneObj {
  fun: [Function: fun],
  syb: Symbol(foo),
  a: undefined,
  b: NaN,
  c: Infinity,
  reg: /^abc$/,
  date: 2020-09-09T04:31:06.705Z,
  set: Set { 1, 2, 3, 4 },
  map: Map { 'name' => '张三', 'title' => 'Author' },
  text: 'aaa',
  value: { a: { b: 2 } }
}
obj {
  fun: [Function: fun],
  syb: Symbol(foo),
  a: undefined,
  b: NaN,
  c: Infinity,
  reg: /^abc$/,
  date: 2020-09-09T04:31:06.705Z,
  set: Set { 1, 2, 3, 4 },
  map: Map { 'name' => '张三', 'title' => 'Author' },
  text: 'aaa',
  value: { a: { b: 3 } }
}