# 手写深拷贝

js 中,由于数据存储方式不同,对于引用数据而言,分为浅拷贝和深拷贝。浅拷贝为只是对堆数据的地址进行拷贝,而深拷贝是对引用数据的内容进行拷贝。

# 浅拷贝

let obj = {foo: {foo: 'foo'}, bar: 'bar'};
let arr = [1,2,3];

let obj1 = obj; // obj1的任意修改都会影响到obj
let obj2 = Object.assign({}, obj); // 只能实现一层的深拷贝
let obj3 = {...obj}; // 只能实现一层的深拷贝

let arr1 = arr;
let arr2 = arr.concat([4,5,6]); // [1,2,3,4,5,6]
let arr3 = arr.slice();
let arr4 = [...arr]

# 深拷贝

深拷贝是将引用类型赋值真实的数据,而不仅是赋值一个引用地址。

# JSON.stirngify()

最简单的就是通过JSON.parse(JSON.stringify(obj))

let obj = {foo: {foo: 'foo'}, bar: 'bar'};
JSON.parse(JSON.stringify(obj));

# 手写clone

深度优先一直遍历, 最后返回一个新对象

// 判断是否是引用类型
let isObj = (obj) => {
    return (typeof obj === 'object' || typeof obj === 'array') && obj !== null;
}

let clone = (obj) => {
    let tem = Array.isArray(obj) ? [] : {}; 
    for(let key in obj) {
        tem[key] = isObj(obj[key]) ? clone(obj[key]) : obj[key];
    }
    return tem;
}

完善环、日期、正则不支持拷贝

let isObj = (obj) => {
    return (typeof obj === 'object' || typeof obj === 'array') && obj !== null;
}

// hash为避免循环引用
let clone = function(obj, hash = new WeakMap()) {
  let tempobj, constructor
  constructor = obj.constructor
  // RegExp Date单独处理
  switch (constructor) {
    case RegExp:
      tempobj = new constructor(obj)
      break;
    case Date:
      tempobj = new constructor(obj)
      break;
    default:
      if (hash.has(obj)) return hash.get(obj)
      tempobj = Array.isArray(obj) ? [] : {}
      hash.set(obj, tempobj) // 这里现在是空的 可是后面的修改会影响这里
  }
  for (let key in obj) {
    tempobj[key] = isObj(obj[key]) ? clone((obj[key]), hash) : obj[key]
  }
  return tempobj
}