Javascript实现深拷贝

133 阅读1分钟

实现1

function deepCopy(obj) {
  return JSON.parse(JSON.stringify(obj));
}

测试

var obj = {
  id: 1,  
  name: "jim",
  colors: ['red', 'green', 'blue'], //数组
  childs: { //对象
    id: 2,
    name: 'jim_child_2'
  },
  birth: new Date(), //日期
  rule: /\d+/gi,     //正则
  say: function() {  //函数
    console.log('hello')
  }
}

var obj1 = deepCopy(obj);
console.log(obj1);
//输出
{
  "id": 1,
  "name": "jim",
  "colors": ["red", "green", "blue"],
  "childs": {
    "id": 2,
    "name": "jim_child_2"
  },
  "birth": "2020-06-02T11:03:00.330Z",
  "rule": {}
}

可以看到:
a. 日期对象变成了字符串形式;
b. 正则对象变成了空对象;
c. 函数被去除了; 

实现2

function deepCopy(p, c) {
  var c = c || {};
  for (var i in p) {
    if (typeof p[i] === 'object') {
      c[i] = (p[i].constructor === Array) ? [] : {};
      deepCopy(p[i], c[i]);
    } else {
      c[i] = p[i];
    }
  }
  return c;
}

测试

var obj2 = deepCopy(obj);
console.log(obj2);
//输出
{
  "id": 1,
  "name": "jim",
  "colors": ["red", "green", "blue"],
  "childs": {
    "id": 2,
    "name": "jim_child_2"
  },
  "birth": {},
  "rule": {},
  "say": ƒ ()
}
可以看到:
a. 日期对象变成了空对象;
b. 正则对象变成了空对象;

//添加循环引用 
obj.obj = obj;
var obj3 = deepCopy(obj); //Uncaught RangeError: Maximum call stack size exceeded

实现3

function deepCopy(obj, hash = new WeakMap()) {
  if (obj instanceof RegExp) return new RegExp(obj);  //处理正则对象
  if (obj instanceof Date) return new Date(obj);      //处理日期对象
  if (obj === null || typeof obj != 'object') {
    return obj; // 如果不是复杂数据类型,直接返回
  }
  if (hash.has(obj)) {    //处理循环引用
    return hash.get(obj);
  }
  /**
   * 如果obj是数组,那么 obj.constructor 是 [Function: Array]
   * 如果obj是对象,那么 obj.constructor 是 [Function: Object]
  **/
  let target = new obj.constructor();
  hash.set(obj, target);
  for (let key in obj) {
    if (obj.hasOwnProperty(key)) { //是否是自身的属性
      // 递归
      target[key] = deepCopy(obj[key], hash);
    }
  }
  return target;
}

测试

var obj4 = deepCopy(obj);
console.log(obj4);

//输出
{
  birth: Tue Jun 02 2020 19:21:16 GMT+0800 (中国标准时间) {}
  childs: {id: 2, name: "jim_child_2"}
  colors: (3) ["red", "green", "blue"]
  id: 1
  name: "jim"
  obj: {id: 1, name: "jim", colors: Array(3), childs: {…}, birth: Tue Jun 02 2020 19:21:16 GMT+0800 (中国标准时间), …}
  rule: /\d+/gi
  say: ƒ ()
}